React useMemo与useCallback性能优化实战
说明React中useMemo和useCallback的使用场景、原理与误用风险。在什么情况下应该使用它们?什么情况下使用反而会降低性能?
回答
小字辈
useMemo:缓存计算结果,仅在依赖变化时重新计算
const sortedList = useMemo(
() => items.sort((a, b) => a.date - b.date),
[items]
);
useCallback:缓存函数引用,仅在依赖变化时创建新函数
const handleClick = useCallback(
() => dispatch({ type: 'DELETE', id }),
[id, dispatch]
);
使用场景(应该使用):
- 避免子组件不必要的重渲染:配合React.memo使用,传稳定引用的props
- 父组件传递回调函数给memoized子组件时
- 避免昂贵计算重复执行:大数据排序、过滤、复杂运算
- useMemo只执行昂贵的计算,简单计算(如拼接字符串)不需要
- 作为其他Hooks的依赖:防止useEffect因引用变化而频繁触发
- 避免Context值每次render都重新创建
误用风险(不应该使用):
- 过早优化:useMemo/useCallback本身有内存和计算开销(记录依赖、比较等)
- 简单计算使用useMemo:
useMemo(() => a + b, [a, b])— 缓存开销大于计算开销 - 作为子组件唯一优化手段:若子组件本身渲染开销小,memorization收益为负
- 依赖数组不正确:错过依赖导致bug(stale closure)
React.memo配合使用: React.memo包裹子组件后,仅props变化时重渲染。传递inline对象/函数的父组件会破坏memo:
<Child onClick={() => {}} /> // 每次渲染新函数 → memo无效
<Child onClick={handleClick} /> // useCallback稳定引用 → memo生效
**总结原则:**先测量性能瓶颈,再有针对性地使用memorization。