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

setState → scheduleUpdateOnFiber → render 阶段(包含 beginWork → reconcileChildren ← 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:标记删除映射表中剩余的旧节点(无新节点匹配)

相关推荐
天天喝旺仔1 小时前
浏览器渲染原理:从解析 HTML/CSS、构建渲染树到重排重绘与首屏优化
前端·javascript·css·性能优化·html
Days20502 小时前
时间胶囊项目正式发布
javascript·gpt·php
朱 欢 庆2 小时前
el-table-v2 虚拟表格组件
前端·javascript·vue.js
OpsEye2 小时前
企业大模型用量成本该如何监控和管控?
javascript·ai编程
杨利杰YJlio2 小时前
ITSK 万能驱动 26V5:新驱动批量更新
前端·javascript·后端
y = xⁿ3 小时前
关于Agent智能体开发
开发语言·前端·javascript
事圆则缓3 小时前
Flutter 状态管理框架对比(一):先看地图,再选工具
前端·javascript·flutter
IMPYLH3 小时前
HTML 的 <tfoot> 元素
前端·javascript·html
鬼手点金3 小时前
Claude Code示范案例-修复 Bug 工作流
java·服务器·前端·javascript·bug·openclaw
paopaokaka_luck4 小时前
个人综合管理小程序(echarts数据看板、健康数据记录与趋势查看、目标拆解和进度管理、日程待办与番茄钟、习惯打卡、收支统计、个人生活记录、跨模块智能提醒)
前端·javascript·spring·小程序·数据分析·echarts·生活