虚拟 DOM 的“引用相等性”指 diff 算法中节点可复用时跳过属性更新与子树比对,依据类型一致性和关键标识稳定而非内存地址;React 和 Vue 通过标签名、节点类型等轻量检查判定,满足条件才跳过深度 patch。

虚拟 DOM 的“引用相等性”不是指 JavaScript 中的 === 比较,而是指在 diff 算法中,当新旧两个虚拟节点(VNode)被判定为“可复用”时,框架跳过属性更新和子树比对,直接复用对应的真实 DOM 节点。这种判断依据的是节点类型一致性与关键标识的稳定,而非内存地址相同。
引用相等性的实际判定逻辑
React 和 Vue 的 diff 算法在进入 patch 前,会先执行轻量级节点相等性检查。只有满足以下条件,才认为可以“引用相等”,从而跳过深度 patch:
-
节点类型必须一致:比如都是
div,或都是span;若旧节点是div、新节点是section,则直接卸载重建,不走 patch 流程。 -
元素节点需标签名相同:通过
tagName或type字段严格比对,大小写敏感,且不考虑语义等价(如div和View在 React Native 中不视为相等)。 - 文本节点和 Fragment 节点默认相等:它们没有可变属性,结构上只起容器或内容占位作用,因此无论内容是否变化,都跳过 patch,仅更新其真实 DOM 文本值或忽略。
避免不必要 Patch 的核心技巧
Patch 过程本身包含 props 更新、事件绑定重置、子节点递归 diff 等开销。减少它,关键在于让 diff 算法更早、更稳地做出“跳过”决策:
-
为列表项设置稳定、唯一、不变的
key:避免用index或随机数。当 key 稳定,即使顺序调整,算法也能识别节点复用,避免整组 patch 与重建。 -
避免跨类型替换的 JSX 结构:例如不要在条件渲染中交替返回
<div>和<span>,而应统一外层容器,用display: none或 class 控制显隐。 -
用
Object.is级别的 props 变更控制更新粒度:确保传入组件的 props 是引用不变的(如用useMemo缓存对象、useCallback缓存函数),防止因浅层对象/函数重生成触发无意义 patch。 -
对静态内容使用 Fragment 或
v-memo(Vue)/React.memo(React):让框架明确知道这部分子树无需参与 diff,直接跳过整个子树的 patch 阶段。
什么时候 Patch 无法避免?
以下情况会强制进入完整 patch 流程,无法跳过:
- 组件根节点类型改变(如从
h2变成h3); - 函数组件内部返回的 VNode 根节点每次都不一致(未做 memo 包裹,且 props 引用频繁变动);
- 使用了
v-if/condition && <Comp />导致节点完全消失又重建,而非显隐切换; - 动态 tag 名(如
<component :is="currentTag">)且currentTag值发生变化。

















