两个节点能复用当且仅当类型一致且key严格匹配:类型需为同一tag或组件引用,key须为相同字符串或数字;任一不满足则卸载旧节点并重建新树。

判断两个节点能否复用,核心就两条:类型必须一致,且 key 必须严格匹配。
类型一致是硬门槛
类型指 vnode 的 tag(如 div、span)或组件的构造函数引用(如 MyButton 函数本身)。Vue 和 React 都要求这个值完全相等——不是“看起来像”,而是内存中同一个引用或字符串。
- 旧节点是
<div>,新节点是 <code><p></p>:直接判定为不同类型,整棵子树卸载重建 - 旧节点是组件 A,新节点也是组件 A,但来自不同打包产物或热更新后的新定义:type 引用不一致,仍视为类型不同
- 标签名相同但组件定义不同(比如同名但逻辑已改),不会复用
- 有 key 且 type 相同 → 尝试复用:保留 DOM 元素,只更新属性和子内容
- 有 key 但 type 不同 → 不复用:直接替换整个元素(例如
<input key="user">变成<textarea key="user"></textarea>) - 无 key → 回退到“就地复用”:按索引一一对应 patch,极易引发状态错乱(输入框失焦、选中态丢失、动画中断)
- 新头与旧头的 type 和 key 都相同
- 新尾与旧尾的 type 和 key 都相同
- 新头与旧尾的 type 和 key 都相同(说明节点右移)
- 新尾与旧头的 type 和 key 都相同(说明节点左移)
- 以上都不满足时,再遍历旧列表,用 key 查哈希表找匹配项
- 触发旧节点及其所有子组件的卸载生命周期(
beforeUnmount等) - 销毁对应真实 DOM 节点及绑定事件、计时器等资源
- 从零创建新 vnode 及全部子树,挂载到新位置
key 是复用的必要条件
key 不是可选项,而是建立稳定映射的唯一依据。它必须是字符串或数字,且值完全相等(key="1" 和 key={1} 在某些构造场景下可能因序列化差异导致比对失败)。
双端比较中如何触发复用
在子节点列表 diff 过程中,算法用四个指针(新头、新尾、旧头、旧尾)快速试探匹配。只要满足以下任一条件,就立即复用对应 vnode:
复用失败的后果很明确
一旦 type 或 key 任一不满足,算法不会尝试“打补丁”或合并属性,而是走最彻底的路径:











