Skip to main content

渲染机制与性能优化

面试核心就三句:什么触发渲染 → 渲染了谁 → 怎样缩小范围 / 降低成本

渲染 ≠ 浏览器 paint

React 语境里「渲染」多指:组件函数又执行了一遍,算出新的 Virtual DOM / 元素描述,再交给协调(reconcile)决定改哪些真实 DOM。

浏览器的 layout / paint 是下一步;能少改 DOM、少跑重组件,体感才快。

什么会触发一次更新

常见来源:

  1. 本组件 useState / useReducer 的 set
  2. 父组件 重渲染 → 默认子组件也会再执行(除非被 memo 挡住且 props 浅相等)
  3. Context 值变化 → 所有消费该 Context 的组件更新
  4. 外部 store 订阅(Redux / zustand 选择器命中等)
function Parent() {
const [n, setN] = useState(0)
return (
<>
<button onClick={() => setN(n + 1)}>{n}</button>
<Child /> {/* Parent 一更新,Child 默认也会跑 */}
</>
)
}

协调与 key

同层对比时,React 靠 位置 + type + key 判断节点是否可复用。

// ❌ index 当 key:中间插入/删除会错位复用,状态「串台」
{list.map((item, i) => <Row key={i} item={item} />)}

// ✅ 稳定业务 id
{list.map((item) => <Row key={item.id} item={item} />)}

面试怎么答 key:

  • 帮助 reconcile 识别「是同一个组件实例」
  • 列表重排、插入时,错误 key 会导致 state 挂错行、多余卸载挂载
  • 静态列表用 index 偶尔能混,动态列表别用

React.memo:浅比较 props

const Row = memo(function Row({ item, onSelect }: Props) {
return <div onClick={() => onSelect(item.id)}>{item.name}</div>
})

注意:

  • 默认 浅比较 props
  • 父组件每次 onSelect={() => ...} 新函数 → memo 形同虚设 → 配 useCallback 或把回调稳到 store
  • 不是越多越好:比较本身有成本;先优化「谁在更新、更新面多大」

常见性能手段(按性价比)

手段解决什么备注
状态下沉 / 提升合理范围无关兄弟少更新往往比 memo 更治本
列表虚拟化只渲染可视区大表必问
选择器订阅(zustand 等)少订阅字段状态管理
拆 Context避免「一个大 value 全家重渲染」value 用 memo 或拆多个 Context
useTransition紧急更新优先并发特性
memo + 稳定 props挡纯展示子树先保证 props 引用稳

Context 的坑

// ❌ 每次 Parent 渲染都是新 value 对象 → 所有 Consumer 更新
<Ctx.Provider value={{ user, theme }}>

// ✅ 拆开,或 useMemo value,或别用 Context 扛高频变化的数据

高频、细粒度状态(输入框每个字符)更适合局部 state / 外部 store,而不是顶层 Context。

列表与表格(常考)

  1. key 用稳定 id
  2. 行组件 memo,行 props 尽量原始值或稳定引用
  3. 虚拟列表(只挂载可视行)
  4. 避免在 render 里 list.map 出又过滤又排序的大金句还不缓存——大数据用 useMemo 或上游算好

怎么排查

面试也可提工具链:

  • React DevTools Profiler:谁花了时间、为什么 render(props/hooks 变化)
  • 先看「更新面是否过大」,再看「单次 render 是否过重」

面试速答清单

  1. 父更新子为什么也更新? → 默认递归渲染;memo + props 不变可跳过。
  2. memo 失效最常见原因? → 内联对象/函数 props 每次新引用。
  3. key 用 index 有什么问题? → 列表变序时复用错乱,局部 state 错位。
  4. Context 性能问题? → Provider value 变,所有消费者更新;高频数据慎用大 Context。
  5. 优化顺序? → 减更新范围 → 减渲染成本 → 再考虑 memo/虚拟列表/并发特性。

上一篇:Hooks 核心与常见坑 · 下一篇:Fiber 与调度直觉