把"为什么用、怎么用、用错了怎么办"一次讲透,附 React 19 自动优化前瞻。
一、useMemo 是什么?
一句话:
useMemo = 记住(缓存)昂贵计算结果,只在依赖变化时重新计算。
js
const memoValue = useMemo(() => {
return heavyCompute(a, b);
}, [a, b]);
- 第 1 个参数:计算函数,必须返回一个值。
- 第 2 个参数:依赖数组 ,React 用
Object.is
比对。 - 返回值:缓存值,依赖不变就复用。
二、使用场景 3+1
场景 | 示例 | 收益 |
---|---|---|
昂贵计算 | 大数据过滤 / 排序 / 图表计算 | 避免每次渲染重算 |
稳定引用 | 把对象/数组传给子组件 | 配合 React.memo 减少子组件重渲染 |
函数缓存 | 返回函数时用 useCallback 语法糖 |
防止子组件 props 变化 |
React 19 之前 | 手动优化瓶颈 | React 19 编译器将自动处理 |
三、实战:Todo 列表性能优化
问题:每次添加 todo,都重新过滤 1000 条数据
jsx
function TodoList({ todos, filter }) {
// ❌ 每次渲染都执行 filterTodos
const visibleTodos = filterTodos(todos, filter);
return visibleTodos.map(todo => <li key={todo.id}>{todo.text}</li>);
}
解决:useMemo 缓存过滤结果
jsx
function TodoList({ todos, filter }) {
const visibleTodos = useMemo(
() => filterTodos(todos, filter),
[todos, filter]
);
return visibleTodos.map(todo => <li key={todo.id}>{todo.text}</li>);
}
依赖
[todos, filter]
不变,filterTodos 只在依赖变化时运行。
四、常见误区与对策
误区 | 后果 | 对策 |
---|---|---|
依赖项漏写 | 缓存值不更新 | 使用 ESLint react-hooks/exhaustive-deps |
过度使用 | 缓存成本 > 计算成本 | 先写简单代码,后优化 |
返回函数 | 误用 useMemo(() => fn) |
改用 useCallback(fn, deps) |
五、React 19 之后:还要手动用吗?
React 19 编译器 已能 自动记忆化:
- 大部分场景 无需手写
useMemo
/useCallback
。- 仅在 第三方库要求引用稳定 或 极端昂贵计算 时手动使用。
六、一键记忆化模板
tsx
import { useMemo } from 'react';
export function useExpensiveValue<T>(factory: () => T, deps: any[]): T {
return useMemo(factory, deps);
}
// 用法
const data = useExpensiveValue(() => heavyCompute(a, b), [a, b]);
七、一句话总结
useMemo = "计算缓存" ,只在依赖变化时重算;React 19 之前手动优化瓶颈,之后让编译器兜底。