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

发布: (2026年1月9日 GMT+8 02:08)
8 分钟阅读
原文: Dev.to

看起来您只提供了来源链接,而没有贴出需要翻译的正文内容。请把您想要翻译的文本(包括 Markdown 格式)粘贴在这里,我会按照要求把它翻译成简体中文并保留原有的格式。

“性能阶段”。

你不再担心让东西能工作,而是开始担心让东西快速工作。你开始像他们欠你钱一样盯着重新渲染,打开 React DevTools 的频率比打开 Slack 还高,最后在 Google 上搜索:

“如何防止 React 中的重新渲染?”

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

  • useMemo
  • useCallback
  • memo

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

或者……你是这么认为的。

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

今天我将带你了解一些关于 React 中记忆化的并不明显的误区,并使用这个仓库作为我们的实验场:

👉 Repo: (link omitted in original)

如果你对任何内容有异议——或者有什么点拨到你了——请在评论里(礼貌地)大声说出来。

在我们变得花哨之前,先达成一些事实

React 组件在以下情况下会重新渲染:

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

有些人会再加一条规则:

  1. 属性(props)改变

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

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

误解 #1

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

简短回答: 不会。

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

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

memoized-component.tsx

memoized-component.tsx code content

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

App.tsx

app.tsx code content

(若有所思地点头)

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

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

现在点击 count 按钮:

Rerender mess

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

“但是函数没有变化啊!”

正确。金星 ⭐ 函数引用是稳定的。

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

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

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

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

Rerender solved

没有重新渲染。现在我们实现了之前以为已经实现的目标。

教训:未对组件进行 memo 化 的情况下仅 memo 化 props 对重新渲染毫无作用。

误解 #2

“如果我对组件进行 memo 化,我就安全了”

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

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

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

你可以自行测试:

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

痛苦的真相

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

Bottom line

理解 何时 以及 何种内容 进行 memo 化至关重要。使用 useCallback/useMemo 保持 prop 引用的稳定,并且仅在确信 props 在渲染之间真的保持不变时才 memo 包装组件。

Memoization 有:

  • 心理成本
  • 维护成本
  • 有时甚至会带来性能成本

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

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

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

最后的思考(来自亲身体会的人)

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

我没有做到的是:

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

Memoization 并不是魔法。
它只是一种工具。

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

如果我有什么说错、理解有误,或者这篇文章让你对 Memoization 有了新的认识,留下评论吧。我真的很想听听你的想法。

下次见 👋

Back to Blog

相关文章

阅读更多 »

构建旅行社页面

项目概述 昨天我完成了 freeCodeCamp 响应式网页设计课程中的 Travel Agency 页面实验。该实验提供了一个关于 fini…的示例。