我想深入研究一下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]);
}
示例(在渲染1万个组件时,请谨慎打开):https://codesandbox.io/embed/quizzical-sun-92qnw
要将性能与useReducer解决方案进行比较: https://codesandbox.io/s/nifty-hodgkin-gdo2g
Reducer解决方案要快得多(因为reducer的引用永远不会改变,但是我在所有函数I上都使用useCallback)作为回调传递,所以我不应该与第一个示例有相同的结果吗?>
答案 0 :(得分:1)
解决了这个问题,而不是像下面这样声明我的toggleTodo
函数:
const toggleTodo = useCallback(
id => {
setTodos(
todos.map(todo => {
return todo.id === id ? { ...todo, toggled: !todo.toggled } : todo;
})
);
},
[todos]
);
在这种情况下,待办事项是相互依赖的,并且只要待办事项在变化,这都将获得新的参考,因为我们的浅层参考将有所不同,因此所有内容都将重新呈现。
所以解决方案:
const toggleTodo = useCallback(
id => {
setTodos(oldTodos =>
oldTodos.map(todo => {
return todo.id === id ? { ...todo, toggled: !todo.toggled } : todo;
})
);
},
[]
);
我们的useState 2nd参数可以是值或函数回调。通过使用函数回调,待办事项将不再是依赖关系,我们将能够避免这些重新渲染(实际上这些不是重新渲染,而是重新计算吗?)