React19.x 一个示例来看 Diff 算法

setStatescheduleUpdateOnFiberrender 阶段(包含 beginWorkreconcileChildren ← Diff 发生处 → completeWork → commit 阶段 → DOM mutation。

第一轮遍历(从左到右快速匹配,复杂度 O(n)): 同时遍历新旧节点数组,尽可能复用 key 和 type 都相同的前缀节点。如果遇到 key 相同但 type 不同的情况,React 会直接丢弃旧节点并基于新的 React Element 生成全新 Fiber(旧节点放入 deletions 数组待删除),但遍历并不会终止------这说明 React 对待"key 相同、类型变了"的策略是继续往后尝试匹配。如果遇到 key 和 type 都不相同的情况,则立即结束遍历。

第二轮遍历(处理边界):

  • 情况一 :旧节点有剩余,新节点已遍历完 → 将剩余旧节点标记为 Deletion
  • 情况二:新节点有剩余,旧节点已遍历完 → 为剩余新节点创建新的 Fiber;

第三轮遍历(处理剩余节点): 如果第二轮结束后还有新旧节点未被处理,进入第三轮:

两者都有剩余 → 将剩余旧节点按 key 放入 Map,然后遍历剩余新节点,从 Map 中寻找可复用的节点。在这轮遍历中,React 通过维护 lastPlacedIndex(上一个未移动节点在旧数组中的最大索引)来判断节点是否需要移动。

示例

js 复制代码
import { useState } from 'react';

const RenderArray = () => {
  const [array, setArray] = useState<string[]>(['A','B','C','D','E']);

  return (
    <div key="render-array">
      <h1>RenderArray</h1>
      <button onClick={() => setArray(['A','B','E','D','C','F'])}>Set Array</button>
      <ul>
        {array.map((item) => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </div>
  );
};
export default RenderArray;

reconcileChildrenArray

阶段 1:第一轮遍历(同步遍历新旧节点,快速复用同位置节点)

1、A节点

updateSlot 复用节点

updateElement

placeChild。负责确定新 Fiber 节点在 Fiber 树中的位置,并根据情况标记该节点是需要移动、插入还是保持原位,同时返回更新后的 lastPlacedIndex 值。

A 节点,不需要移动。

2、B节点 与A 节点一样的逻辑

3、新节点 E 、旧节点 C,两者 不同

退出当前第一阶段

阶段 2:处理边界情况(旧节点耗尽 或 新节点遍历完)

情况 2.1:新节点遍历完(newIdx === newChildren.length)

情况 2.2:旧节点遍历完(oldFiber === null)

当前情节跳过,进入第三阶段。

阶段 3:第三轮遍历(键映射表复用 + 计算节点移动)

步骤1:构建剩余旧节点的键映射表(key → Fiber)

步骤2:遍历剩余的新节点,从映射表中查找可复用节点

1、E节点, 找到复用。

不移动

2、找到 D 节点,复用,需要移动

3、找到 C节点,复用,需要移动

4、F节点,新节点,标记插入

创建新节点 createFiberFromElement

标记插入

步骤3:标记删除映射表中剩余的旧节点(无新节点匹配)

相关推荐
_柳青杨33 分钟前
深入理解 JavaScript 事件循环
前端·javascript
大家的林语冰6 小时前
ES5 凉凉,Babel 8 正式发布,默认不再编译为 ES5 和 CJS......
前端·javascript·前端工程化
光影少年7 小时前
react批量更新、同步/异步更新场景
前端·react.js·掘金·金石计划
YFF菲菲兔8 小时前
completeRoot 源码解析
react.js
weedsfly8 小时前
异步编程全景与事件循环——彻底搞懂 JS 执行机制
前端·javascript
用户1733598075378 小时前
纯前端 PDF 数字签名实战:Vue 3 + pdf-lib 在浏览器里完成签名嵌入
前端·javascript
JieE21219 小时前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE21219 小时前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
kyriewen1 天前
我用 AI 一周写完了整个项目,上线第一天就崩了——这是我踩过最贵的 5 个坑
前端·javascript·ai编程
Larcher1 天前
AI Loop:让AI像人一样自主完成任务的核心机制
javascript·人工智能·设计模式