使用useCallback做性能优化
面试速答
- 以下内容以 React 18 为准。
useCallback的本质不是“缓存函数逻辑”,而是 缓存函数引用。- 它通常用于避免因为函数引用每次都变,导致子组件或 effect 无意义更新。
什么时候有价值
1. 配合 React.memo
const Child = React.memo(function Child({onSave}: {onSave: () => void}) {
return <button onClick={onSave}>保存</button>
})
const onSave = useCallback(() => {
submit(form)
}, [form])
如果父组件每次 render 都创建新函数,子组件浅比较可能失效。
2. 作为 Hook 依赖
某些自定义 Hook 或 effect 依赖某个回调时,稳定引用能减少无意义重建。
什么时候没必要
1. 子组件本来就会重渲染
如果子组件不做任何记忆化,父组件刷新后它本来就会重新执行,这时单独稳定回调意义不大。
2. 回调本身很简单,且没有向下传递压力
为了一个很轻的函数强加 useCallback,只会让依赖关系更复杂。
useCallback 和 useMemo 的关系
可以把它理解成:
useCallback(fn, deps)
约等于:
useMemo(() => fn, deps)
一个缓存“结果”,一个缓存“函数引用”。
React 18 下的成熟答法
不要把 useCallback 说成“性能银弹”。更稳的表达是:
当函数引用稳定性会影响子组件记忆化、Hook 依赖或订阅重建时,
useCallback才真正有价值。
标准答法
问:useCallback 主要优化什么?
答:优化的是函数引用稳定性,避免把“父组件每次 render 都创建新函数”传播成下游无意义更新或副作用重建。
易错点
- 误以为
useCallback能减少函数创建成本本身。 - 不看场景全量套用。
- 依赖写不全导致回调拿旧值。
速记要点
useCallback缓存函数引用,不缓存执行结果。- 典型场景:
React.memo子组件、Hook 依赖。 - 没有引用稳定诉求时,不必强上。