useMemo 和 useCallback 的区别是什么?
一句话终极结论#
useMemo 缓存「函数返回的值」,useCallback 缓存「函数本身」 两者都是为了防止重复创建引用,解决 React 重复渲染问题。
1. 核心对比表#
| 特性 | useMemo | useCallback |
|---|---|---|
| 缓存什么 | 值 / 计算结果 | 函数本身 |
| 返回什么 | 计算好的数据 | 缓存后的函数 |
| 解决问题 | 避免重复昂贵计算 | 避免子组件重复渲染 |
| 触发时机 | 依赖变化时重新计算 | 依赖变化时更换函数引用 |
| 等价写法 | useCallback(fn, deps) ≈ useMemo(() => fn, deps) |
2. 代码直观对比#
① useCallback(缓存函数)#
给函数做缓存,保证函数引用不变
主要用于传递给子组件的函数,配合 React.memo 防止子组件重渲染。
// 缓存函数本身,依赖不变,函数地址就不变
const handleClick = useCallback(() => {
console.log(count);
}, [count]);
// 传递给子组件,引用不变 → 子组件不重渲染
<Child onClick={handleClick} /> jsx② useMemo(缓存值)#
给计算结果做缓存,避免每次渲染都重算 主要用于耗时计算、对象、数组。
// 缓存计算出来的值,依赖不变,值就不变
const expensiveValue = useMemo(() => {
return count * 1000; // 模拟耗时计算
}, [count]);
// 缓存对象,保证引用不变
const userInfo = useMemo(() => ({ name: 'Tom', age: 20 }), []);jsx3. 最核心的本质#
React 靠「引用地址」判断是否变化
- useCallback:让函数地址不变
- useMemo:让数据/对象地址不变
地址不变 → React.memo 判定 props 不变 → 子组件不重渲染
4. 最佳使用场景#
✅ useCallback 场景#
需要把函数传给子组件时:
const fetchData = useCallback(() => {
axios.get('/api');
}, []);
// 传递给被 memo 包裹的子组件
<Table fetchData={fetchData} />jsx✅ useMemo 场景#
- 耗时计算(过滤、排序大量数据)
- 传递给子组件的对象/数组
const options = useMemo(() => ({ pageSize: 10 }), []);
<Filter options={options} />jsx5. 满分答案#
- useCallback 缓存函数本身,用于优化子组件渲染;
- useMemo 缓存计算结果,用于优化重复计算;
- 两者都是依赖驱动,依赖不变,缓存就不变;
- 核心目的都是保持引用地址稳定,配合 React.memo 防止无效重渲染。
总结#
- 想缓存函数 → 用
useCallback - 想缓存数据/计算值 → 用
useMemo - 都是性能优化工具,不要滥用