useMemo 和 useCallback 的区别?什么时候该用?
区别
useMemo缓存计算结果(值)useCallback缓存函数引用
// useMemo:缓存值
const sortedData = useMemo(() => {
return data.sort((a, b) => a - b)
}, [data])
// useCallback:缓存函数
const handleClick = useCallback(() => {
console.log(id)
}, [id])
// useCallback 本质是 useMemo 的语法糖
const handleClick = useMemo(() => () => {
console.log(id)
}, [id])什么时候用
useMemo 适用场景:
- 昂贵的计算
const result = useMemo(() => {
return heavyComputation(data) // 计算耗时 > 1ms
}, [data])- 稳定引用对象(作为其他 Hook 的依赖或子组件的 prop)
const config = useMemo(() => ({ endpoint: '/api', timeout: 5000 }), [])useCallback 适用场景:
- 传递给被 React.memo 包裹的子组件
const Child = React.memo(({ onClick }) => {
console.log('Child render')
return <button onClick={onClick}>Click</button>
})
function Parent() {
const [count, setCount] = useState(0)
// ✅ 使用 useCallback,count 变化时 Child 不会重新渲染
const handleClick = useCallback(() => {
console.log('clicked')
}, [])
return <Child onClick={handleClick} />
}- 作为 useEffect 的依赖
const fetchData = useCallback(() => {
api.get(id)
}, [id])
useEffect(() => {
fetchData()
}, [fetchData])什么时候不用
// ❌ 简单计算不需要 useMemo
const doubled = useMemo(() => count * 2, [count])
// 直接写就行
const doubled = count * 2
// ❌ 不传递给子组件的函数不需要 useCallback
const handleLocalClick = useCallback(() => { ... }, [])
// 直接定义即可
const handleLocalClick = () => { ... }性能权衡
- useMemo/useCallback 本身有内存开销和依赖比较开销
- 对于简单计算和不被引用的函数,使用它们反而更慢
- 不要过度优化:只在真正需要时使用
React 19 变化
React 19 编译器(React Compiler)可以自动优化 memo,未来可能不需要手动使用 useMemo/useCallback。