Skip to content

vue和react的diff区别

🕒 Published at:

节点比较策略:双端 vs 单向

Vue(双端比较)

采用首尾双指针同时向中间移动,优先对比头部/尾部节点(头-头、尾-尾、头-尾、尾-头)。若匹配成功则复用节点并移动指针;若无匹配,则基于 最长递增子序列(LIS) 算法处理中间节点的移动。 优势 对节点位置变化(如列表重排)更高效。例如,将末尾节点移到开头时,Vue 只需移动一个节点。

React(单向比较)

采用从左到右的单指针遍历,按顺序对比新旧节点。依赖 key 和 lastIndex 判断复用:若新节点 index < lastIndex,则标记移动。 劣势 末尾节点移到开头时,需将前方所有节点右移,导致 O(n) 移动开销。

示例场景:列表 [A, B, C, D] → [D, A, B, C] Vue:移动 D 到开头(1 次操作)。 React:将 A/B/C 依次右移(3 次操作)。

节点复用逻辑:属性敏感性 vs 类型优先

Vue

若节点标签类型相同但关键属性(如 className)不同,视为不同节点,删除并重建。例如 <div class="a"> 变为 <div class="b"> 会触发重建。 原因 Vue 认为属性变化可能影响布局,需彻底更新。

React

只要标签类型和 key 相同,仅更新变化的属性(如修改 className),不重建节点。 优势 减少 DOM 操作,但对样式变化敏感的场景可能需手动优化。

更新机制:同步 vs 批量

Vue

在 Diff 过程中同步更新真实 DOM(如调用 insertBefore),最后处理删除。 影响:更早呈现变化,但频繁更新可能引发布局抖动。

React

先收集变更形成 effect list,再批量更新 DOM(先删除 → 更新 → 插入)。结合 Fiber 架构支持中断/恢复更新,适合高优先级任务。

优化策略:编译时 vs 运行时

Vue 3 的编译时优化

静态提升(Hoisting) :编译阶段标记静态节点,跳过运行时 Diff。 Patch Flags:动态节点标记变化类型(如文本/属性),仅对比标记部分。 LIS 算法:最小化节点移动次数。

React 的运行时优化

Fiber 时间分片:将 Diff 拆分为可中断的微任务,避免阻塞主线程。 手动优化:依赖开发者通过 shouldComponentUpdate 或 React.memo 避免无效更新。

总结

Vue 和 React Diff 算法的最根本区别在于:

👉 Vue 通过双端比较 + LIS 算法 + 编译时优化,优先减少节点移动次数,尤其擅长动态列表更新;

👉 React 依赖单向遍历 + Fiber 分片,强调批量更新和开发者手动控制,适合结构稳定的应用。

选择建议:

高频列表操作(如拖拽排序)选 Vue;

需精细控制更新逻辑或集成复杂状态管理选 React。

vue 和 react 分别怎么diff的

Vue 的 Diff 过程(双端比较 + LIS)

初始化指针: 旧: [a, b, c, d] → 头指针=0(a),尾指针=3(d)

新: [b, c, a, f] → 头指针=0(b),尾指针=3(f)

双端比较: 头头对比:a ≠ b → ❌ 尾尾对比:d ≠ f → ❌ 头尾对比:a ≠ f → ❌ 尾头对比:d ≠ b → ❌

非理想模式(建立 key-index 映射):

新节点映射:

  • 查找新头节点 b: 旧索引=1 → 移动 b 到旧头指针前(a 之前) 标记旧位置1为 undefined,新头指针右移 → 新: [c, a, f]

  • 查找新头节点 c: 旧索引=2 → 移动 c 到旧头指针前(a 之前) 标记旧位置2为 undefined,新头指针右移 → 新: [a, f]

  • 头头对比:a = a → 复用,旧头指针右移 → 旧: [d],新头指针右移 → 新: [f]

  • 头头对比:d ≠ f → ❌

  • 查找新头节点 f: 旧索引不存在 → 创建 f 并插入旧头指针前(d 之前)

清理旧节点:

删除未处理的旧节点 d

最终结果:

js
移动节点: b, c (2)
创建节点: f (1)
删除节点: d (1)

react

初始化映射:

创建旧节点 key-index 映射:{a:0, b:1, c:2, d:3} 初始化 lastIndex = 0(记录当前已复用的最大旧索引)

遍历新节点:

  • 新节点 b(key=b) :

    • 旧索引 = 1(lastIndex=0)
    • 1 > 0 → 复用旧节点 b,不移动
    • 更新 lastIndex = max(0,1) = 1
  • 新节点 c(key=c) :

    • 旧索引 = 2(lastIndex=1)
    • 2 > 1 → 复用旧节点 c,不移动
    • 更新 lastIndex = max(1,2) = 2
  • 新节点 a(key=a) :

    • 旧索引 = 0(lastIndex=2)
    • 0 < 2 → 移动节点 a 到当前位置(c 之后)
    • 不更新 lastIndex(仍为 2)
  • 新节点 f(key=f) :

    • 旧索引不存在 → 创建新节点 f

清理旧节点: 删除未复用的旧节点 d

最终结果:

js
移动节点: a (1)
创建节点: f (1)
删除节点: d (1)

结论

React 优势:当节点从头部移到尾部时(如 a 从开头移到末尾),只需移动 1 次。

Vue 优势:当节点整体轮转时(如 [a,b,c,d] → [d,a,b,c]),Vue 只需移动 1 次(d),React 需移动 3 次。