React.memo 和重渲染监控:组件不要白干活
·
某些组件每次父组件更新就“无辜”重渲染,明明数据没变,却还是重新走一遍逻辑。
React.memo就是用来阻止这种“白干活”的神器。今天我们从监控重渲染开始,到React.memo、useMemo、Profiler一起上阵,教你把性能问题揪出来并解决。
🎯 为什么组件会重新渲染?
- 父组件重新渲染 → 子组件默认也重渲染。
- props 引用发生变化(即使内容一样)。
- context/state 改变,影响所有订阅它的组件。
我们的目标是让“没有变化的数据”跳过渲染,让“确实变化的数据”尽早渲染。
🧪 React.memo 最基础用法
const UserCard = React.memo(function UserCard({ user }) {
console.log('render', user.name);
return <div>{user.name}</div>;
});
- React 会对比
userprop 的引用是否变化。 - 如果引用没变,就直接复用上一次的结果。
🧠 自定义对比函数
有时 user 是一个新对象,但内容没变。可以传入 areEqual:
const UserCard = React.memo(
function UserCard({ user }) { /* ... */ },
(prevProps, nextProps) => prevProps.user.id === nextProps.user.id
);
- 注意自定义函数要非常轻量,不然得不偿失。
🔍 监控渲染:为什么总是多渲染?
1. 为什么要监控?
- 没有数据支持的优化只是“心理安慰”。
- Profiler 能告诉你:组件渲染了几次、耗时多少。
2. 如何使用 React Profiler
- 打开 React DevTools → Profiler。
- 点击“开始录制”。
- 触发页面操作。
- 查看每个组件的渲染情况。
3. 快速定位“罪魁祸首”
- 寻找渲染次数过多的组件。
- 观察 props 值是否频繁变动(例如函数、数组)。
🧩 综合案例:带筛选的用户列表
const UserList = React.memo(({ users, onSelect }) => {
console.log('UserList render');
return (
<ul>
{users.map((user) => (
<li key={user.id} onClick={() => onSelect(user)}>
{user.name}
</li>
))}
</ul>
);
});
function App() {
const [keyword, setKeyword] = useState('');
const [selected, setSelected] = useState(null);
const filteredUsers = useMemo(() => {
return data.filter((user) => user.name.includes(keyword));
}, [keyword]);
const handleSelect = useCallback((user) => setSelected(user), []);
return (
<div>
<input value={keyword} onChange={(e) => setKeyword(e.target.value)} />
<UserList users={filteredUsers} onSelect={handleSelect} />
{selected && <UserDetail user={selected} />}
</div>
);
}
UserList用React.memo。users和onSelect用useMemo/useCallback保持引用稳定。- Profiler 截图:输入框改变时,
UserList只在keyword变化时重渲染一次。
🧯 注意事项
| 问题 | 解决方案 |
|---|---|
| 组件内部仍依赖 context | 即使用了 memo 也会跟着 context 更新 |
| memo 组件传递匿名函数 | 用 useCallback 包裹 |
| 数据浅比较不够 | 用 areEqual 或在父组件处理数据 |
| 过度 memo 化 | 小型纯展示组件不用 memo,成本大于收益 |
🔁 配合 Suspense 和 Concurrent Mode
- 在 React 18 并发模式下,
React.memo仍然有用。 - Suspense 的 fallback 渲染也会触发子组件渲染,要关注渲染次数。
✅ 博客标题灵感
- 《React.memo 真能优化性能吗?我用 Profiler 测了 3 个例子》
- 《告别无意义重渲染:React.memo + useCallback 实战指南》
- 《React 重渲染排查:一步一步用 Profiler 切出性能肥肉》
🏁 小练习
- 实际项目里找一个重复渲染的列表,用 Profiler 记录优化前后数据。
- 写一个
useWhyDidYouUpdateHook,调试时输出 props 变化详情。 - 对比
React.memo和memo+areEqual的性能差异,写成图表。
更多推荐


所有评论(0)