Skip to content

React 性能优化

React 组件为什么会重渲染?如何系统减少无效重渲染?

减少重渲染的关键是缩小更新影响范围,而不是机械地给所有组件加 memo。

适合阶段:高级前端 / 资深前端核心能力:更新传播 · 状态边界 · 性能取舍

面试官想考什么

  • 哪些更新会触发组件重新评估? 考察 React 更新模型。
  • 父组件更新是否一定导致子组件 DOM 更新? 考察 render 与 commit 边界。
  • Context 和 memo 为什么容易被误用? 考察优化边界。
  • 你会如何定位无效渲染? 考察工具使用能力。

一句话回答

text
组件重渲染通常来自自身 state、父组件更新、Context 或外部 store 订阅变化,治理重点是缩小状态所有权和订阅范围,再用 memo 或缓存处理确实昂贵的部分。

面试回答详解

1. 常见触发来源

  • 自身 state 或 reducer 更新。
  • 父组件重新评估并重新创建 props。
  • 消费的 Context value 变化。
  • useSyncExternalStore 或状态库订阅值变化。
  • key、路由或条件变化导致组件卸载重建。

2. 先解决结构问题

text
状态放置位置 -> 订阅范围 -> props 引用 -> 派生计算 -> memo

把高频 state 下沉到真正需要它的组件,拆分大组件,避免把整个页面包在一个高频 Provider 中。派生数据能计算就不要复制存储。

3. memo 的边界

父组件重新评估不代表子组件一定提交 DOM 更新;React.memo 通过 props 比较跳过部分子树,但 Context、内部 state 和外部订阅仍可触发更新。自定义比较函数也有 CPU 成本。

4. 验证方式

用 Profiler、why-did-you-render 类工具或开发日志找出更新原因,再用 Performance 和 RUM 验证。不要用 render 次数单独作为目标。

可直接背诵的 30 秒回答

text
React 组件可能因为自身 state、父组件更新、Context、外部 store 或 key 变化而重新评估。我的处理顺序是先下沉高频状态、缩小订阅范围、拆分组件和稳定数据流,再对昂贵子树使用 memo。判断是否有效要结合 Profiler 的提交耗时、浏览器长任务和真实用户交互指标,而不是只看 render 次数。

扩展知识

更新范围模型

text
更新源 -> 订阅者 -> React render -> commit -> layout/paint

面试官追问链

追问一:父组件重渲染,子组件一定重渲染吗?

  • 考察点:是否避免绝对化表述。
  • 回答方向:默认会重新评估子树,但 memo、组件边界和更新路径可能跳过部分工作;是否提交 DOM 还要另看。

追问二:给父组件加 memo 能解决子组件慢吗?

  • 考察点:是否能找到真正更新源。
  • 回答方向:只有父组件本身被无意义更新且 props 稳定时有帮助;如果子组件自身 state、Context 或 store 变化,父组件 memo 无法解决。

追问三:为什么对象 props 每次都变?

  • 考察点:引用稳定性意识。
  • 回答方向:render 中创建了新对象、数组或函数;应先评估是否需要稳定引用,不能为了形式到处缓存。

推荐阅读

基于 MIT 协议开源