5月28日 03:16

什么是 Virtual DOM?React 为什么用它替代直接操作 DOM?

Virtual DOM 是一棵用 JavaScript 对象描述的 DOM 树。React 状态变化时,先在内存里生成新的虚拟 DOM 树,和旧树做 diff,算出最小变更集,再批量更新真实 DOM。这么做的核心原因是——直接操作真实 DOM 太贵了,一次 appendChild 可能触发重排+重绘+合成三层渲染管线。Virtual DOM 把"手动精确定位变更"这件事自动化了:你只管声明 UI 长什么样,React 负责高效地同步到真实 DOM。顺带一提,正因为 UI 描述和渲染层解耦,React Native 才能复用同一套组件模型渲染原生控件。

追问

Virtual DOM 一定比直接操作 DOM 快吗?

不是。单改一个文本节点,el.textContent = 'xxx' 比 Virtual DOM diff 整棵子树更快。Virtual DOM 的价值在复杂 UI 场景:几十个组件同时更新时,它能自动算出最优更新路径,避免开发者手动 diff。所以它不是"最快",而是"在绝大多数场景下足够快,且不需要你操心"。

React 的 diff 算法怎么做到 O(n) 的?

朴素的树 diff 是 O(n³),React 用三个策略降到 O(n):

策略含义
类型不同直接重建<div> 变成 <span>,整个子树丢弃重建,不跨类型 diff
key 标识稳定性通过 key 追踪同一组子元素中的身份,避免错位复用
只比较同级不跨层级比较,父亲和儿子不会互相匹配

代价是可能遗漏极少数跨层级移动的最优解,但实际场景中跨层级移动极少,这个权衡是值得的。

Vue 的 Virtual DOM 和 React 有什么区别?

Vue 的响应式系统精确追踪了"哪个组件依赖了哪个数据",数据变了可以直接跳过无关组件的 diff。React 默认从触发更新的组件开始整棵子树 diff,需要 React.memouseMemo 手动优化。但 React 18 并发模式可以在调度层面拆分任务、让高优先级更新插队,这是 Vue 目前没有的。

实际项目里 Virtual DOM 有什么常见的坑?

  1. index 做 key:列表增删元素时 diff 错位,导致非预期复用和状态错乱。用唯一 ID 做 key。
  2. 大列表没有虚拟化:Virtual DOM 只解决 diff 效率,不解决渲染量。几千行的长列表必须上 react-window / react-virtuoso 做虚拟滚动。
  3. 不必要的重渲染:父组件 state 变了,即使子组件 props 没变也会 diff。React.memouseMemo 不是过早优化,是 React 开发的日常操作。
标签:React