Я хочу немного углубиться в ловушки React и пытаться понять, как сделать мои компоненты более производительными. Хотя я думаю, что использую useCallback
в нужном месте, мое приложение работает очень медленно, потому что происходит слишком много обновлений.
Что я мог бы улучшить, чтобы только один или два компонента изменились, а не воссоздали все это?
function createTodos(number) {
const todos = [];
for (let i = 0; i < number; i++) {
todos.push({
id: i,
toggled: !(i % 4)
});
}
return todos;
}
function Todos() {
const [todos, setTodos] = useState(() => createTodos(10000));
const toggleTodo = useCallback(
id => {
setTodos(
todos.map(todo => {
return todo.id === id ? { ...todo, toggled: !todo.toggled } : todo;
})
);
},
[todos]
);
return useMemo(
() =>
todos.map(todo => (
<Todo
key={todo.id}
todoId={todo.id}
toggled={todo.toggled}
toggleTodo={toggleTodo}
/>
)),
[todos, toggleTodo]
);
}
function Todo({ todoId, toggled, toggleTodo }) {
const toggle = useCallback(() => toggleTodo(todoId), [todoId, toggleTodo]);
return useMemo(() => {
const style = {
background: toggled ? "green" : "red",
margin: 2,
padding: 4
};
return (
<div style={style} onClick={toggle}>
{todoId}
</div>
);
}, [todoId, toggled, toggle]);
}
Пример (открывать с осторожностью, так как я рендеринг 10k компонентов): https://codesandbox.io/embed/quizzical-sun-92qnw
Чтобы сравнить производительность с решением useReducer:
https://codesandbox.io/s/nifty-hodgkin-gdo2g
Решение для редуктора намного быстрее (потому что ссылка на редуктор никогда не меняется, НО я использую useCallback для всех функций I), передается в качестве обратного вызова, поэтому разве я не должен иметь тот же результат, что и в первом примере?