useMemo使用场景
- 缓存昂贵的计算结果:当一个组件中有需要大量计算才能得出的值,并且这个计算的依赖项不 经常变化时,我会用 useMemo 来缓存结果。比如,对一个巨大的列表进行多重筛选、排序和 格式化,这个操作可能很耗时,如果每次渲染都重新计算,会造成界面卡顿。
const heavyComputedValue = useMemo(() => {
// 假 设 list 非 常大,这个 操 作 很 耗 时
return list.filter(item => item.isActive).map(item => ({ ...item, formatted: true }));
}, [list]); // 仅 在 list 变化 时 才 重 新 计 算
- 对象或数组的引用稳定:当需要向下传递一个对象或数组作为 props 时,如果这个对象或数 组是在渲染函数中直接创建的,那么每次渲染都会产生一个新的引用。这会导致接收该 prop 的子组件(尤其是被React.memo 优化的组件)无效地重新渲染。 useMemo 可以确保只有在依赖项变化时才创建新的对象/数组引用。
const style = useMemo(() => ({
color: 'blue',
fontWeight: 'bold'
}), []); // 空 依 赖数组 ,style 对 象 的 引用 永 不 改变6
return <ChildComponent style={style} />;
useCallback 的使用场景:
- 稳定化传递给子组件的函数:这与 useMemo 的第二点类似,但针对的是函数。如果一个函数 被作为 prop 传递给一个被React.memo 优化的子组件,或者这个函数是子组件useEffect 的依赖项,那么就应该用 useCallback 来包裹它。这可以防止因为父组件渲染导致函数被重新创建,从而避免子组件不必要的重新渲染。
const handleItemClick = useCallback((id) => {
console.log('Clicked item:'
, id);
// ... do something with id ...
}, []); // 空 依 赖 ,函数引用 永 不 改变
return <MemoizedListComponent onItemClick={handleItemClick} />;
滥用useCallback或useMemo存在的问题
滥用 useMemo 和 useCallback 会带来几个问题,甚至可能让性能变得更差:
- 增加内存开销:每一次使用 useMemo 或 useCallback ,Re a ct 都需要存储缓存的值/函数以 及它的依赖项数组。如果滥用,会导致不必要的内存占用。
- 增加初始渲染 和更新时的计算成本:在每次组件渲染时,Re ct 仍然需要调用这些 a Hooks,比较前 后两次的依赖项数组是否发生了 变化。对于简单的计算或函数 ,这个“比较”的开销本身可能就比 重新创建一个函数或值要大。
- 代码可读性和维护 性下降:满篇的 useMemo 和 解。开发者需要时刻思考依赖项是否填写正确,增加了心智负担。 useCallback 会让代码变得臃肿、难以理