React性能优化总览

React 中渲染、列表、引用稳定性与缓存相关优化点的总览入口。

#tech / dev / frame #resource / react #type / synthesis #status / growing

[!info] related notes

React性能优化总览

React 性能优化最容易走偏的地方,是还没定位瓶颈,就先到处加 memouseMemouseCallback。真正有效的优化,通常从理解渲染来源开始。

先建立正确前提

  • 重渲染本身是 React 的正常工作方式
  • 真正昂贵的,通常是重复计算、大列表、低效副作用或错误状态设计
  • 优化应该服务真实瓶颈,而不是服务心理安慰

真正更重要的优化顺序

  1. 先保证数据流和依赖正确
  2. 再删除没必要的 state 和 Effect
  3. 再看状态边界、组件边界、列表结构
  4. 最后才考虑 memouseMemouseCallback

很多时候最有效的优化不是“缓存更多”,而是“少建模错误的状态”。

最常见的几个优化入口

状态边界

状态放得越合理,无意义联动越少。先看 react-component-design-principles

渲染来源

先定位为什么会 rerender,再决定是否需要优化。见 React组件渲染与重渲染

计算缓存

昂贵计算才值得考虑 react-use-memo

引用稳定

只有当函数引用变化真的影响子组件或依赖项时,才需要 react-use-callback

组件级跳过渲染

react-memo 适合稳定 props 的组件边界,但不是默认必加项。

列表渲染

长列表和错误 key 经常比普通 rerender 更容易出问题。见 react-list-rendering-and-key

面试里怎么回答“React 性能优化”

这题最容易答偏成“背 API 清单”。更稳的答法应该先讲原则,再讲常见瓶颈,再讲工具。

一个更完整的回答可以是:

React 性能优化我一般先看是不是状态设计、渲染边界或副作用设计出了问题,而不是先到处加 memo。真正常见的瓶颈通常是状态放得太高导致联动重渲染、大列表渲染过重、引用不稳定让 memo 失效、或者 Effect 里做了不必要的工作。优化顺序上我会先定位重渲染来源,再优化状态边界和组件边界,最后才考虑 React.memouseMemouseCallback 这些缓存手段。

面试官真正想听什么

  • 你是不是知道 rerender 本身不是原罪
  • 你会不会先定位问题,而不是盲目加缓存
  • 你是否理解状态边界、列表优化、引用稳定这些更本质的点

高频优化场景

1. 状态放得太高

  • 父组件一个 state 变化,整片子树都跟着 rerender
  • 这时更该考虑状态下沉、局部化,而不是先加 memo

2. 列表太大

  • 大列表渲染和更新成本高
  • 要看 key 是否稳定
  • 必要时考虑虚拟列表

3. 引用不稳定

  • 父组件每次渲染都新建对象和函数
  • 子组件用了 memo 也可能照样 rerender

4. 昂贵计算

  • 只有真的有重计算成本时,useMemo 才更有意义

5. Effect 做了太多事

  • 错误的 Effect 往往比“没加 memo”更容易造成性能浪费

一个更工程化的排查顺序

  1. 先用 React DevTools Profiler 看谁在频繁 rerender
  2. 再判断是 state、props、context 还是列表结构导致
  3. 再决定是否需要缓存、拆分组件或重构状态位置

一条实用优化顺序

  1. 先确认慢在哪里
  2. 再看是不是状态设计或列表结构问题
  3. 最后才考虑 memouseMemouseCallback 这类缓存手段

一个常见误区

很多人把优化理解成:

  • 到处加 useMemo
  • 到处加 useCallback
  • 到处包 React.memo

但如果:

  • 子组件本身不重
  • 计算本身不贵
  • 引用稳定并没有带来实际收益

这些缓存只会增加代码复杂度。

常见误区

  • 把 React 优化理解成“尽量不 rerender”
  • 还没定位瓶颈就全局加 memo
  • 以为 useCallback 的价值是“少创建函数”,而不是“稳定引用”
  • 子组件本身不重、计算本身不贵时,仍然到处加 useMemo / useCallback / React.memo

最短记忆方式

React 优化不是“减少一切渲染”,而是减少真正昂贵且没有价值的工作。

创建于 2026/3/19 更新于 2026/5/27