使用 useMemo 与 useCallback 提升性能
使用 useMemo 缓存开销较大的计算,使用 useCallback 保持函数引用稳定,从而避免不必要的子组件重新渲染。
使用 useMemo 与 useCallback 提升性能 是 CoddyKit 上的免费 Frontend Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Frontend Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Frontend Academy 课程共包含 4 节课。
React 的默认行为
默认情况下,只要组件自身的状态发生变化,或其父组件重新渲染,React 就会重新渲染该组件。即使子组件的属性没有变化,它们也会重新渲染。对于大多数组件来说这完全没问题——React 的运行速度很快。
useMemo——记忆化昂贵的值
useMemo(fn, deps) 会缓存计算结果。只有依赖项发生变化时,该函数才会运行。请将它用于开销较大的计算,以避免每次渲染都重复计算。
const expensiveResult = useMemo(() => {
return items.filter(item => item.category === category).sort((a, b) => a.price - b.price);
}, [items, category]);
// Only recalculates when items or category changesuseCallback——记忆化函数
useCallback(fn, deps) 会返回一个记忆化函数,只有依赖项发生变化时才会改变其引用。将回调传递给深层嵌套组件或经过记忆化的组件时,可以使用它。
const handleDelete = useCallback((id: string) => {
setItems(prev => prev.filter(item => item.id !== id));
}, []); // stable reference — empty deps because only setItems is used
<ItemList items={items} onDelete={handleDelete} />React.memo——跳过重新渲染
React.memo(Component) 会包装一个组件,使其只有在属性发生变化时才重新渲染(进行浅比较)。将它与 useCallback 结合,可提供稳定的回调属性。
const MemoItem = React.memo(function Item({ text, onDelete }: ItemProps) {
console.log('Item rendered:', text); // only logs when props change
return <li>{text} <button onClick={onDelete}>×</button></li>;
});
// onDelete must be stable (from useCallback) for memo to help何时不应进行 NOT 优化
过早优化是一个陷阱。useMemo 和 useCallback 需要付出代价:闭包开销和依赖项比较开销。对于便宜的操作(例如筛选 10 个项目),额外开销会超过收益。请先确认存在真实的性能问题,再进行优化。
优化前先进行性能分析
在添加记忆化之前,请使用 React DevTools 性能分析器测量实际的渲染时间。性能分析器会显示哪些组件耗时最长,以及它们渲染了多少次。请根据证据而不是假设进行修复。
使用 useMemo 保持稳定引用
useMemo 还可以用于保持引用稳定——目的不是提高计算本身的性能,而是避免下游的记忆化逻辑或副作用不必要地重新执行。
// Without useMemo, this creates a new array every render:
const config = useMemo(() => ({ endpoint: '/api', timeout: 5000 }), []);
// Without memoization, useEffect would re-run on every render:
useEffect(() => { initSDK(config); }, [config]);useCallback 的依赖项
useCallback 遵循与 useEffect 相同的依赖项规则。请包含回调所使用的外部作用域中的每个变量。状态设置函数(来自 useState)始终稳定,无需放入依赖项中。
useMemo 与 useCallback 的关系
useCallback(fn, deps) 等价于 useMemo(() => fn, deps)。它们使用的是同一种机制——useCallback 只是专门用于记忆化函数的语法简写。
列表项目记忆化
一种常见模式是:当列表很大且经常重新渲染时,记忆化列表项目组件。请从 useCallback 传递稳定的回调,以免使记忆化失效。
const MemoRow = React.memo(Row);
const handleEdit = useCallback((id) => edit(id), []);
const handleDel = useCallback((id) => remove(id), []);
{rows.map(row => (
<MemoRow key={row.id} row={row} onEdit={handleEdit} onDelete={handleDel} />
))}上下文值记忆化
请记忆化传递给上下文提供者的值,以避免每当提供者的父组件重新渲染时,所有消费者都重新渲染。
const value = useMemo(() => ({ user, login, logout }), [user]);快速检查
useCallback 的作用是什么?
总结:useMemo 与 useCallback
useMemo 会缓存开销较大的计算值。useCallback 会缓存函数引用。当属性没有发生浅层变化时,React.memo 会跳过重新渲染。将三者结合使用,可以提升组件级别的性能。请先进行性能分析——过早记忆化会增加复杂度,却没有收益。稳定的引用可以避免下游副作用和记忆化逻辑重复执行。
常见问题解答
「使用 useMemo 与 useCallback 提升性能」课时是免费的吗?
是的 — 「使用 useMemo 与 useCallback 提升性能」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Frontend Academy 课程的其余内容,请升级到 CoddyKit PRO。 Frontend Academy 课程共包含 4 节课。
「使用 useMemo 与 useCallback 提升性能」这节课中我会学到什么?
使用 useMemo 缓存开销较大的计算,使用 useCallback 保持函数引用稳定,从而避免不必要的子组件重新渲染。 你通过在浏览器中直接运行的动手代码来练习 Frontend Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Frontend Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Frontend Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「使用 useMemo 与 useCallback 提升性能」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Frontend Academy 课中编写并运行代码吗?
能。每节 Frontend Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 使用 useContext 管理全局状态
- 使用 useReducer 管理复杂状态
- 使用 useMemo 与 useCallback 提升性能
- 自定义 Hook:提取可复用逻辑