Но насколько велико влияние на производительность, если я делаю это 1000 раз? Есть ли заметное снижение производительности?
Это зависит от приложения. Если вы просто визуализируете 1000 строк счетчиков, это, вероятно, нормально, как видно из фрагмента кода ниже. Обратите внимание, что если вы просто изменяете состояние отдельного <Counter />
, только этот счетчик будет перерисован, остальные 999 счетчиков не будут затронуты.
Но я думаю, что вы обеспокоены несущественными вещами здесь. В реальных приложениях вряд ли будет отображаться 1000 элементов списка. Если ваше приложение должно отображать 1000 элементов, возможно, что-то не так с вашим дизайном.
Вы не должны отображать 1000 предметов в DOM. Обычно это плохо с точки зрения производительности и UX, с современными JavaScript-фреймворками или без них Вы можете использовать методы работы с окнами и отображать только те элементы, которые видите на экране, остальные элементы вне экрана могут находиться в памяти.
Реализуйте shouldComponentUpdate
(или useMemo
), чтобы другие элементы не перерисовывались в случае повторного рендеринга компонента верхнего уровня.
Используя функции, вы избегаете накладных расходов на классы и некоторых других связанных с классами вещей, о которых вы не знаете, потому что React делает это автоматически. Вы теряете некоторую производительность из-за вызова некоторых хуков в функциях, но вы получаете некоторую производительность и в других местах.
Наконец, обратите внимание, что вы вызываете хуки useXXX
и не выполняете функции обратного вызова, которые вы передали в хуки. Я уверен, что команда React хорошо поработала над тем, чтобы облегчить вызовы с помощью ловушек, вызовы не должны быть слишком дорогими.
А как можно было бы избежать этого?
Я сомневаюсь, что был бы сценарий реального мира, в котором вам нужно будет создавать объекты с состоянием тысячу раз. Но если вам действительно нужно, было бы лучше поднять состояние до родительского компонента и передать обратный вызов значения и увеличения / уменьшения в качестве опоры для каждого элемента. Таким образом, ваши отдельные элементы не должны создавать обратные вызовы модификатора состояния и могут просто использовать реквизит обратного вызова от своего родителя. Кроме того, дочерние компоненты без сохранения состояния упрощают реализацию различных известных оптимизаций перфорации.
Наконец, я хотел бы повторить, что вам не следует беспокоиться об этой проблеме, потому что вы должны стараться избегать попадания в такую ситуацию вместо того, чтобы справляться с ней, опираясь на такие методы, как использование окон и разбиение на страницы - только загружая данные, которые нужно отобразить на текущей странице.
const Counter = ({ initial }) => {
const [count, setCount] = React.useState(initial);
const increase = React.useCallback(() => setCount(count => count + 1), [setCount]);
const decrease = React.useCallback(
() => setCount(count => (count > 0 ? count - 1 : 0)),
[setCount]
);
return (
<div className="counter">
<p>The count is {count}.</p>
<button onClick={decrease} disabled={count === 0}>
-
</button>
<button onClick={increase}>+</button>
</div>
);
};
function App() {
const [count, setCount] = React.useState(1000);
return (
<div>
<h1>Counters: {count}</h1>
<button onClick={() => {
setCount(count + 1);
}}>Add Counter</button>
<hr/>
{(() => {
const items = [];
for (let i = 0; i < count; i++) {
items.push(<Counter key={i} initial={i} />);
}
return items;
})()}
</div>
);
}
ReactDOM.render(
<div>
<App />
</div>,
document.querySelector("#app")
);
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>