浅谈React的Diff算法,简单易懂!

react16之前,主要是通过递归遍历Vdom树来查找不同。对有变化的部分重新生成真实的DOM。

在react16之后,则是引入了新的架构Fiber架构 ,在Reconciler(协调器)中会进行Diff算法。流程如下:

  1. 第一次渲染的时候,不进行diff,而是直接将vdom转成Fiber,在内存中构workInProgressFiber 树,构建完成之后用它来替换currenFiber,再去通知渲染器进行渲染。

  2. 后续更新渲染时,会将生成的VDOM和旧的Fiber进行对比,决定生成怎样的新的Fiber(就是能复用的复用,多余的删除,新增的新增)。完成之后对新生成的Fiber再进行DOM操作。

具体的diff是如何比对的呢?

其实一句话总结就是, Fiber中diff算法的核心是查找复用节点。

如:我们有一个父节点,底下有四个节点。VDOM如下:

开始渲染的时候,第一次,会被协调器转换为Fiber树。然后进行渲染到页面。

如果这时候组件更新了,新的VDOM是 A C E F后。

这时候diff算法就要开始操作了。

复制代码
​1. 先循环让新的VDOM跟旧的第一次的Fiber来进行对比,看看有没有能复用的点。如果有,就继续遍历,如果没有,则停止遍历。 

2. 判断新的VDOM有没有遍历结束,如果结束了,就把旧的Fiber中的节点删除即可。若新的没有遍历完,则会进行第二次遍历。 

3. 第二次遍历的时候,把旧的中的fiber剩下的节点,放入一个map中,然后遍历新的Vdom剩下的节点。看看当前遍历的Vdom有没有存在于这个Map里面,若存在,则表明可以复用,打上更新的标记。 

4. 遍历完新的Vdom后,旧的Fiber剩下的节点都可以打上删除标记,新的Vdom中新增的节点则打上新增的编辑。
​

详细说明:

第一次循环:

进行的是新Vdom跟旧Fiber中第一个节点的对比。发现这时候是可以复用的,则打上更新标记。然后继续遍历,新的VDOM的下一个节点C,发现跟旧的Fiber中的节点B不能复用。这时候,第一次遍历结束。 然后判断新的Vdom中的节点是否遍历结束了,如果没有,则进行第二次遍历。

第二次循环:

  1. 把旧的Fiber中,剩下的节点中的 B C D 放入一个map中,key就是当前节点的可以。

  2. 继续遍历 新的VDOM中剩下的节点,同样去找能不能复用的节点,斌如发现只有C节点能在Map中找到,则打上更新标记。

整体遍历结束后。

map就剩下 B D两个节点。(新的中没有) 打上删除标记。

新的VDOM中 E跟 F 则为新增节点。(旧中没有。)打上新增标记。

最后去执行渲染。就是 A与 C为更新复用。 B跟 D为删除。 E 跟 F 为新增。

总体来说:

复制代码
diff核心就是查找复用节点:
 第一轮遍历时,线性一一对比,若新Vdom的当前节点和旧的Fiber当前节点不能复用,则终止遍历。
 第二次遍历时,将旧的Fiber剩余节点放入Map,继续遍历新的VDom中的节点,寻找 复用节点,打上更新标记,  遍历结束后,map中剩余的打上删除标记,新的VDOM中,没有找到复用的则为新增标记。
 
 最后根据变化,生成新的Fiber。然后执行阶段渲染。
相关推荐
专业抄代码选手2 小时前
08|Fiber 上的 `useState`:状态终于属于具体组件
前端·javascript·react.js
默_笙2 小时前
😭 Vibe Coding 翻车实录:AI 编程为什么必须先写"剧本"
前端·javascript
LEE2 小时前
原来 Claude Code 最厉害的工具,一行代码都不写
前端·后端
parade岁月2 小时前
为了给表格加虚拟滚动而选了 vxe-table?也可以考虑下这个
前端·vue.js
打呵欠的猫2 小时前
一个 Hook 让 AI 每次写文件前自动检查编码规范,违规代码再也提交不进来
前端·ai编程·代码规范
恋猫de小郭3 小时前
Android 17 + OkHttp 5.5.0 ,全新 ECH 下你的 HTTPS 域名可以请求时被安全隐藏
android·前端·flutter
后除3 小时前
从零到一: 创建一个 TypeScript 7 项目
前端·webpack·typescript
lerhxx3 小时前
我用 R3F 手搓了一个能走进去的 3D 迷宫简历(上):从选型架构到迷宫生成算法
前端·javascript·three.js
还有多久拿退休金3 小时前
不调多模态,纯文本大模型如何给系统操作配上截图
前端·llm·aigc
hunterandroid4 小时前
HarmonyOS WebSocket 实战:断线重连、心跳保活与连接状态机设计
前端