React 列表性能优化
React 列表性能问题的主要来源,以及 key、渲染边界、虚拟列表和数据更新方式之间的关系。
#tech / dev / frame
#resource / react
#type / synthesis
#status / growing
[!info] related notes
React 列表性能优化
React 列表性能问题很少只靠一个 memo 就能解决,真正要看的是列表为什么慢:是节点太多、更新太频繁,还是每次都让整片列表重复执行。
一句话定义
React 列表优化的核心是减少不必要的节点数量、减少不必要的重新执行,以及保证每一项的身份稳定。
列表为什么会慢
- 一次性渲染的节点太多
- 列表项更新时整片列表都重新执行
key不稳定导致节点复用失效- 父组件每次都传入新的对象或函数 props
最常见的优化方向
先保证 key 稳定
key影响 React 识别列表项身份- 错误
key会放大重排、状态错位和无效更新问题
再缩小渲染边界
- 不要把只影响单行的状态放到过高层
- 把局部交互尽量留在局部组件里
- 必要时再考虑
React.memo这类边界优化
再看 props 身份是否稳定
- 列表项接收的新对象或新函数可能让优化失效
- 优化前先确认是不是真的存在重复执行成本
节点过多时考虑虚拟列表
- 如果瓶颈来自 DOM 数量太大,虚拟列表往往比细抠 Hook 更有效
- 它本质上是减少同时存在的真实节点数量
常见误区
- 看到列表卡顿就先全量加
useMemo和useCallback - 把列表性能问题全归因于 React 本身
- 只看 JavaScript 执行,不看真实 DOM 数量和滚动渲染成本
最短记忆方式
先保身份稳定,再缩边界,节点太多就上虚拟列表。
面试要点
来自 react-list-performance-optimization-interview-question 的面试视角整理。
一句话回答
React 长列表优化通常先看 key 是否稳定、状态和渲染边界是否合理,再看 props identity 是否导致无效更新;如果瓶颈来自节点数量过多,就优先考虑虚拟列表。
最稳的回答主线
- 第一层看列表项身份:
key要稳定 - 第二层看渲染范围:别让局部交互带动整片列表一起执行
- 第三层看引用稳定性:对象和函数 props 可能让优化边界失效
- 第四层看节点数量:DOM 太多时用虚拟列表比细节缓存更有效
一个更完整的面试表达
可以这样答:
长列表优化我一般不会一上来就说
memo。我会先分四层看:
第一层是key是否稳定,先保证列表项身份正确;
第二层是状态和渲染边界是否合理,避免局部操作带动整片列表一起重算;
第三层才看对象和函数 props 的引用稳定性;
如果问题的根源是同时渲染了太多 DOM 节点,那重点通常不是“让每一项更便宜”,而是直接上虚拟列表做窗口化。
一个典型答题结构
- 先保证
key正确 - 再收紧状态边界
- 再考虑
React.memo、useMemo、useCallback - 节点量太大就上虚拟列表
为什么虚拟列表经常是关键
因为当瓶颈来自“同时挂了几千个节点”时,哪怕每个节点都稍微优化一点,收益也可能不如直接减少可见节点数量。
面试里容易加分的一句
如果问题主要是同时渲染了上千个节点,那重点往往不是“让每个节点更便宜”,而是“不要同时渲染这么多节点”。
常见追问
- 为什么 index 不适合当
key React.memo在列表里什么时候值得用- 虚拟列表解决的是 React 问题还是 DOM 问题
最短记忆方式
先看身份和边界,再看引用,节点太多就做窗口化。