题目重点:用官方渲染三阶段和列表状态归属解释 UI 比较,避免把 Virtual DOM 说成总会更快。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 这里把 Virtual DOM 当作常见面试口语,具体解释基于 React 的组件渲染结果/树与 DOM commit;不声称有一份与浏览器 DOM 一一等价且始终驻留的公共 API 对象。
- 以普通客户端 React 列表 UI 为例,具体调度和内部数据结构会随版本变化。
解题路线
- 先分三步:state/props 变化触发更新,React 调用组件计算下一次 UI(render),然后仅在 commit 阶段把必要差异应用到 DOM。React 官方说明重渲染不一定修改 DOM。
- 组件 render 必须保持纯计算,不能在 render 中操作外部系统;订阅、网络或手动 DOM 应在恰当的 Effect/事件路径。
- 比较/复用的关键是组件类型、在树中的位置及 key。稳定业务 ID 作为列表 key,可让移动后的项目保有正确的 state;数组索引 key 在重排时可能把输入状态挂到错误项目。
- 性能分清 JS render 工作、DOM commit 工作和浏览器 layout/paint;避免无证据说 Virtual DOM 一定比手写 DOM 快。用 React Profiler 找受影响子树,必要时拆组件/稳定 props/缓存昂贵纯计算。
手动走一遍
列表有 A、B 两项,各自内有输入框,按业务 ID 作为 key 后把顺序从 [A,B] 改为 [B,A],state 仍属于各自项目;若用位置索引当 key,React 可把第一个位置原 A 的 state 错挂给现在的 B。render 可计算出新树,但只有最终变化需要 commit 到 DOM。
规模与取舍
一次更新的渲染/比较成本随实际参与渲染的子树和列表规模变化,DOM 写入量取决于差异;不能由题名推出严格通用 Big-O。大列表应配合稳定 key、拆分组件、必要时虚拟滚动和性能测量。
易错点与追问
容易失分的边界
- 把 render 与浏览器 paint/DOM mutation 当同一阶段。
- 声称‘Virtual DOM 让一切更新都比手写 DOM 快’。
- 认为组件每次 render 都会重建所有实际 DOM 节点。
- 动态列表用数组索引 key,重排后 state 归属错乱。
- 在 render 中发请求或改 DOM,破坏纯渲染要求。
继续深挖
- 同一组件在同位置换 key 为什么会重置 state?
- 为什么 props 未变时子组件仍可能 render,何时使用 memo?
- 如何用 Profiler 证明一次优化真减少了用户可感知延迟?
- React render 被中断后,未 commit 的 DOM 会怎样?
技术参考
- React 官方 Render and Commit:说明触发、渲染、提交及重渲染不总改 DOM。
- React 官方 State 与 Key:说明组件状态与树位置/key 的关联。
