0Pricing
Frontend Academy · 课时

使用 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 changes

useCallback——记忆化函数

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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 useContext 管理全局状态
  2. 使用 useReducer 管理复杂状态
  3. 使用 useMemo 与 useCallback 提升性能
  4. 自定义 Hook:提取可复用逻辑
← 返回 Frontend Academy