React性能优化 | 别再让你的 React 页面卡成PPT了！useMemo必学

做过 React 项目的应该都遇到过这种情况：开发时页面丝般顺滑，但一上线数据量大了就卡得要死。点个按钮要等三秒，比我家猫起床都慢。

别急着甩锅给后端，今天说个 React 里经常被忽视但很有用的东西 —— useMemo。

这玩意儿名字听起来像 "有记忆"，其实就是组件的省电模式。

useMemo 是什么

想象你有个同事，每次问他复杂问题都要算半天。关键是每问一次他就重算一遍，哪怕数据压根没变。

useMemo就像给这个同事装了个记忆：上次算过的结果记着呢，你要不要直接用？

本质就是缓存计算结果，只要依赖没变就直接返回旧结果，不重复计算。

语法长这样：

Copy
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

只有当a或b改了才重新算，否则直接返回上次的结果。

什么时候用

1. 计算很重的时候

比如处理5000条订单数据做排序、过滤、统计。这种操作每次都跑风扇都要起飞，而组件一天要渲染几十次。

Copy
const processedData = useMemo(() => {
return heavyProcess(orders); // 耗时操作
}, [orders]); // 只有orders变了才重算

这样就从每次渲染都算变成只算一次。

2. 给子组件传对象或数组

子组件用了React.memo但还是一直重渲染？很可能是因为传过去的 prop 每次都是新的引用。

比如这样：

Copy
// 每次渲染都创建新数组，哪怕内容一样
<MyComponent filters={[{ type: "active" }]} />

解决方法：

Copy
const stableFilters = useMemo(() => [{ type: "active" }], []);
<MyComponent filters={stableFilters} />;

这样对象地址就不变了，React.memo才能正常工作。

3. 作为其他 Hook 的依赖项

Copy
const config = { userId, theme };

useEffect(() => {
fetchUserData(config);
}, [config]); // 问题来了！

每次渲染config都是新对象，useEffect就会重复触发。

解决：

Copy
const config = useMemo(() => ({ userId, theme }), [userId, theme]);

useEffect(() => {
fetchUserData(config);
}, [config]);

现在只有userId或theme变了config才更新。

useMemo vs useCallback

这两个容易搞混：

Hook | 缓存的是啥？ | 使用场景
useMemo | 一个值 | 复杂计算、对象 / 数组、作为依赖
useCallback | 一个函数本身 | 防止函数变化导致子组件重渲染

Copy
// useMemo：缓存"计算结果"
const total = useMemo(() => items.reduce(sum), [items]);

// useCallback：缓存"函数本身"
const handleClick = useCallback(() => doSomething(id), [id]);

常见坑点

依赖项写错

Copy
useMemo(() => expensive(), [{}]); // 每次都是新对象！
useMemo(() => expensive(), [[]]); // 每次都是新数组！

确保依赖项是稳定的值。

滥用 useMemo

不是所有计算都要缓存。如果只是简单的a + b，用useMemo反而浪费。

React 官方说过：过早优化是万恶之源。先找到性能瓶颈再用useMemo。

总结

什么时候用：

计算很重

传给memo子组件的对象 / 数组

作为其他Hook的依赖项

记住：它是瑞士军刀，不是创可贴。

页面卡了别急着换框架，先看看是不是该给 useMemo 发工资了。