React 中的 Memoization:或者说我以为我优化了我的应用(但大多只是感觉自己很有成效)

发布: (2026年1月9日 GMT+8 02:08)
8 min read
原文: Dev.to

Source: Dev.to

请提供您希望翻译的完整文本内容(文章正文),我会将其准确地翻译成简体中文并保留原有的 Markdown 格式、代码块以及技术术语。谢谢!

“性能阶段”。

你不再担心让东西能运行,而是开始担心让它们运行得
你开始对重新渲染侧目而视,好像它们欠你钱一样,打开 React DevTools 的频率比打开 Slack 还高,最终去 Google 搜索:

“How to prevent re‑renders in React?”

React 以其无尽的智慧,给出了三个魔法词:

  • useMemo
  • useCallback
  • memo

你阅读几篇博客文章,以 1.25× 速率观看 YouTube 视频,在代码里撒上一点 memoization,就像调味料一样,然后——voilà——✨ 已优化。

或者……你这么认为。

那就是我——很长一段时间的我。我 感觉 自己在写高性能的 React,但我决定不再只凭感觉,而是 观察 React 在几种情境下的实际表现。结果让我谦卑:我一直在以看似有效的方式“优化”我的应用,却并没有实现我以为的效果。

今天我将带你了解一些 关于 React 中 memoization 的不太明显的误区,并使用这个仓库作为我们的练习场:

👉 Repo:

如果你对任何内容有异议——或有共鸣——请在评论中(礼貌地)大声说出来。

在我们深入之前,让我们先达成一些共识

当以下情况发生时,React 组件会重新渲染:

  1. 它的 内部状态改变
  2. 它的 父组件重新渲染

有些人会添加第三条规则:

  1. 它的 属性(props)改变

个人认为第 2 条已经涵盖了这一点。如果你不同意,欢迎在评论中与我争论。我持开放态度。 😄

记住这两条规则——我们会像讲师一次又一次指着同一张幻灯片并说 “这会出现在考试里” 那样反复提到它们。

误解 #1

“将记忆化的值传入组件可以防止重新渲染”

简短回答: 不会。

详细回答: 让我来说明我为什么也会陷入这个误区。

切换到仓库中的 without-memoized-component 分支。你会看到两个组件:

memoized-component.tsx

memoized-component.tsx code content

(假装我在戏剧性地指着它)

App.tsx

app.tsx code content

(若有所思地点头)

注意 App.tsx 中的一点重要内容:我们在把函数作为 prop 传下去之前使用了 useCallback。此时,过去的我已经在庆祝了。

“函数已经被记忆化。React 不会重新渲染子组件。我是性能天才。”

现在点击 count 按钮:

Rerender mess

子组件 每一次 都会重新渲染。

“但是函数没有变化!”

没错。金星 ⭐ 函数引用是稳定的。

但请记住规则。回到规则 #2:当 父组件重新渲染 时,子组件也会重新渲染。父组件的状态变了,所以父组件重新渲染,子组件随之重新渲染。

useCallback 并没有让你失望——是你的期望失望了(我也是)。在这种情况下,useCallback 基本上是情感支持:它让你 感觉 更好,却并没有真正阻止任何事情。

“那……我们该怎么解决?”

很简单。给子组件加上 memo 包装,然后刷新应用(真的刷新),再点击按钮:

Rerender solved

不再重新渲染。现在我们实现了之前以为已经实现的效果。

教训: 仅仅记忆化 props 而不记忆化组件本身 对重新渲染毫无帮助。

误解 #2

“如果我对组件使用 memo,我就安全了”

memo 只在 属性未改变 时阻止重新渲染。React 使用 浅层比较 来检查这一点。因此,如果你做了以下任意操作,React 会看到一个新的引用并重新渲染:

  • 传入内联函数
  • 传入新创建的对象
  • 传入未被 memo 化的派生值

此时,你的 memo 包装器仅是装饰性的。

你可以自己测试:

  1. App.tsx 中移除 useCallback
  2. 点击按钮
  3. 观察渲染计数像在做有氧训练一样上升

痛苦的真相

未对传入的值进行 memo 化 的情况下对组件进行 memo 化,就像锁上前门却把窗户敞开一样。看起来很安全——其实并不是

结论

了解 何时 以及 什么 需要进行记忆化至关重要。使用 useCallback/useMemo 来保持 prop 引用的稳定,并且仅在确信 props 在渲染之间真正保持不变时才用 memo 包装 组件。

记忆化有:

  • 认知成本
  • 维护成本
  • 有时甚至会带来性能成本

它只有在以下情况下才会发挥作用:

  • 重新渲染代价高
  • props 稳定
  • 你已经测量到真实的问题(而不仅仅是感觉)

我将在另一篇文章中更深入探讨 何时 记忆化真正有意义。

最后的思考(来自亲身经历的教训)

很长一段时间,我以为自己写的 React 性能很好,因为我用了正确的工具。

我没有做到的是:

  • 观察行为
  • 质疑假设
  • 理解 为什么 React 会重新渲染

记忆化并不是魔法。
它只是一个工具。

和所有工具一样,只有真正了解它的工作原理时,它才能发挥最佳效果。

如果我有什么说错的、误解的,或者这篇文章让你对记忆化有了不同的认识,欢迎留言。我真的很想听听你的想法。

下篇再见 👋

Back to Blog

相关文章

阅读更多 »