当前位置: 首页 > news >正文

react中的diff算法

diff算法
对于React团队发现在日常开发中对于更新组件的频率,会比新增和删除的频率更高,所以在diff算法里,判断更新的优先级会更高。对于Vue2的diff算法使用了双指针,React的diff算法没有使用双指针,是因为更新的jsx对象的newChildren为数组的形式,但是和newChildren中每个组件比较的是current fiber,对fiber的兄弟节点是通过silbing来相连的,我们通过下标来去获取下一个newChildren项,但是对于fiber只能通过fiber.silbing来获取对应的项,所以没有使用双指针法来进行diff。

所以React的diff算法的整体逻辑会经历两轮的遍历。

第一轮遍历:
会尝试逐个的复用节点;

第二轮遍历:
处理上一轮遍历中没有处理完的节点。

一、第一轮遍历:
从前往后以此进行遍历,存在三种情况:

  • 若新旧子节点的key和type都相同,则说明可以复用;

  • 若新旧子节点的key相同,但是type不同,这个时候会根据

    reactElement来生成一个全新的fiber,旧的fiber被放入到deletions数组中,回头统一删除,但是注意,此时遍历不回停止;

  • 若新旧子节点的key和type都不相同,则结束遍历。

实例1:
前:

<div>
<div key='a'>a</div>
<div key='b'>b</div>	
<div key='c'>c</div>	
<div key='d'>d</div>	
</div>	

后:

<div>
<div key='a'>a</div>
<div key='b'>d</div>	
<div key='e'>e</div>	
<div key='d'>d</div>	
</div>	

我们发现div.key.a和我们发现div.key.b可以复用,继续往后走
走到div.key.e,我们发现key不同,结束第一轮遍历;

实例2:

<div>
<div key='a'>a</div>
<div key='b'>b</div>	
<div key='c'>c</div>	
<div key='d'>d</div>	
</div>	

更新后:

<div>
<div key='a'>a</div>
<div key='b'>b</div>	
<p key='c'>c</p>	
<div key='d'>d</div>	
</div>	

前面div.keya和div.keyb都会复用,接下来到了第3个节点,我们发现key是相同的,但是type不同,就会将对应的旧的fiberNode放到一个叫deletions中数组中,回头统一删除,然后根据新的react元素创建一个新的FiberNode,但此时的遍历不会结束。
接下来往后面继续遍历,遍历什么时候结束?
到末尾了,也就是遍历完了
或者是和实例1相同,发现key不同。

二、第二轮遍历:
如果第一轮遍历被提前停止了,那么意味着有新的React元素或者旧的FiberNode没有遍历完,此时就会采用第二轮遍历;
第二轮遍历会处理这么三种情况:
只剩下旧子节点:将旧的子节点放到deletions数组里面直接删除掉(删除的情况);
只剩下新的jsx元素:根据RecreatElement元素来创建新的FiberNode节点(新增的情况);
新旧节点都有剩余:
会将剩余的FiberNode节点放到一个map里面,遍历剩余的jsx元素,然后从map中找出可以复用的fiberNode,若能找到就拿来复用(移动的情况)
若不能找到,就新增,然后若剩余的jsx元素都遍历完了,map结构中还有剩余的fiber节点,就将这些fiber节点添加到deletions数组中,之后做统一删除。

例子:

// 之前
abcd// 之后
acdb===第一轮遍历开始===
a(之后)vs a(之前)  
key不变,可复用
此时 a 对应的oldFiber(之前的a)在之前的数组(abcd)中索引为0
所以 lastPlacedIndex = 0;继续第一轮遍历...c(之后)vs b(之前)  
key改变,不能复用,跳出第一轮遍历
此时 lastPlacedIndex === 0;
===第一轮遍历结束======第二轮遍历开始===
newChildren === cdb,没用完,不需要执行删除旧节点
oldFiber === bcd,没用完,不需要执行插入新节点将剩余oldFiber(bcd)保存为map// 当前oldFiber:bcd
// 当前newChildren:cdb继续遍历剩余newChildrenkey === c 在 oldFiber中存在
const oldIndex = c(之前).index;
此时 oldIndex === 2;  // 之前节点为 abcd,所以c.index === 2
比较 oldIndex 与 lastPlacedIndex;如果 oldIndex >= lastPlacedIndex 代表该可复用节点不需要移动
并将 lastPlacedIndex = oldIndex;
如果 oldIndex < lastplacedIndex 该可复用节点之前插入的位置索引小于这次更新需要插入的位置索引,代表该节点需要向右移动在例子中,oldIndex 2 > lastPlacedIndex 0,
则 lastPlacedIndex = 2;
c节点位置不变继续遍历剩余newChildren// 当前oldFiber:bd
// 当前newChildren:dbkey === d 在 oldFiber中存在
const oldIndex = d(之前).index;
oldIndex 3 > lastPlacedIndex 2 // 之前节点为 abcd,所以d.index === 3
则 lastPlacedIndex = 3;
d节点位置不变继续遍历剩余newChildren// 当前oldFiber:b
// 当前newChildren:bkey === b 在 oldFiber中存在
const oldIndex = b(之前).index;
oldIndex 1 < lastPlacedIndex 3 // 之前节点为 abcd,所以b.index === 1
则 b节点需要向右移动
===第二轮遍历结束===最终acd 3个节点都没有移动,b节点被标记为移动

再看个例子:


// 之前
abcd
// 之后
dabc
===第一轮遍历开始===
d(之后)vs a(之前)
key不变,type改变,不能复用,跳出遍历
===第一轮遍历结束===
===第二轮遍历开始===
newChildren === dabc,没用完,不需要执行删除旧节点
oldFiber === abcd,没用完,不需要执行插入新节点
将剩余oldFiber(abcd)保存为map
继续遍历剩余newChildren
// 当前oldFiber:abcd
// 当前newChildren dabc
key === d 在 oldFiber中存在
const oldIndex = d(之前).index;
此时 oldIndex === 3; // 之前节点为 abcd,所以d.index === 3
比较 oldIndex 与 lastPlacedIndex;
oldIndex 3 > lastPlacedIndex 0
则 lastPlacedIndex = 3;
d节点位置不变
继续遍历剩余newChildren
// 当前oldFiber:abc
// 当前newChildren abc
key === a 在 oldFiber中存在
const oldIndex = a(之前).index; // 之前节点为 abcd,所以a.index === 0
此时 oldIndex === 0;
比较 oldIndex 与 lastPlacedIndex;
oldIndex 0 < lastPlacedIndex 3
则 a节点需要向右移动
继续遍历剩余newChildren
// 当前oldFiber:bc
// 当前newChildren bc
key === b 在 oldFiber中存在
const oldIndex = b(之前).index; // 之前节点为 abcd,所以b.index === 1
此时 oldIndex === 1;
比较 oldIndex 与 lastPlacedIndex;
oldIndex 1 < lastPlacedIndex 3
则 b节点需要向右移动
继续遍历剩余newChildren
// 当前oldFiber:c
// 当前newChildren c
key === c 在 oldFiber中存在
const oldIndex = c(之前).index; // 之前节点为 abcd,所以c.index === 2
此时 oldIndex === 2;
比较 oldIndex 与 lastPlacedIndex;
oldIndex 2 < lastPlacedIndex 3
则 c节点需要向右移动
===第二轮遍历结束===

相关文章:

react中的diff算法

diff算法 对于React团队发现在日常开发中对于更新组件的频率&#xff0c;会比新增和删除的频率更高&#xff0c;所以在diff算法里&#xff0c;判断更新的优先级会更高。对于Vue2的diff算法使用了双指针&#xff0c;React的diff算法没有使用双指针&#xff0c;是因为更新的jsx对…...

【医学大模型 尘肺病】PneumoLLM:少样本大模型诊断尘肺病新方法

PneumoLLM&#xff1a;少样本大模型诊断尘肺病新方法 提出背景PneumoLLM 框架效果 提出背景 论文&#xff1a;https://arxiv.org/pdf/2312.03490.pdf 代码&#xff1a;https://github.com/CodeMonsterPHD/PneumoLLM/tree/main 历史问题及其背景&#xff1a; 数据稀缺性问题&a…...

【SpringBootStarter】自定义全局加解密组件

【SpringBootStarter】 目的 了解SpringBoot Starter相关概念以及开发流程实现自定义SpringBoot Starter(全局加解密)了解测试流程优化 最终引用的效果&#xff1a; <dependency><groupId>com.xbhog</groupId><artifactId>globalValidation-spring…...

【射影几何15】python双曲几何工具geometry_tools

目录 一、说明二、​环境问题&#xff1a;如何安装三、实现一个简单的例子四、绘制双曲组五、使用有限状态自动机加快速度六、资源和代码 一、说明 Geometry_tools 是一个 Python 包&#xff0c;旨在帮助您处理和可视化双曲空间和射影空间上的群动作。 该包主要构建在 numpy、…...

机器人抓取 [ 题目/摘要 ] 更新中..

题目&#xff1a;Robotic Grasping of Novel Objects using Visionl 链接&#xff1a;机器人抓取新物体 | IEEE Xplore&#xff08;IEEE的Xplore&#xff09; 【端到端】 摘要&#xff1a;我们考虑抓取新物体的问题&#xff0c;特别是第一次通过视觉看到的物体。抓取以前未知的…...

【51单片机】外部中断和定时器中断

目录 中断系统中断介绍中断概念 中断结构及相关寄存器中断结构中断相关寄存器 外部中断实验外部中断配置软件设计实验现象 定时器中断定时器介绍51 单片机定时器原理51 单片机定时/计数器结构51 单片机定时/计数器的工作方式 定时器配置硬件设计软件设计实验现象 中断系统 本章…...

零售行业供应商数据分发,怎样提高安全性和效率?

零售行业是我国经济发展的重要组成&#xff0c;零售行业包罗万象&#xff0c;如包括汽车零售、日化零售、快消品零售等&#xff0c;不同细分行业的运营模式各不相同&#xff0c;但大体来说&#xff0c;零售行业都具备最基础的供应商和零售商&#xff0c;供应商将商品或服务卖给…...

Windows下Node.js下载安装及环境变量配置教程

Windows下Node.js下载安装及环境变量配置教程 安装版本&#xff1a;node-v18.19.0-x64.msi 文章目录 Windows下Node.js下载安装及环境变量配置教程一、Node.js和NPM简介二、下载地址三、安装步骤四、环境配置五、安装淘宝镜像总结 一、Node.js和NPM简介 1、Node.js &#xf…...

广义表-C语言

广义表&#xff08;Generalized List&#xff09;是一种扩展了线性表的数据结构&#xff0c;它在线性表的基础上增加了元素可以是表的特点。在广义表中&#xff0c;元素不仅可以是单个的数据元素&#xff0c;还可以是一个子表&#xff0c;而子表中的元素也可以是数据元素或其他…...

uniapp+uView 【详解】录音,自制音频播放器

效果预览 代码实现 <template><view class"btnListBox"><view class"audioBox" v-if"audioLength"><u-row><u-col span"2"><u--text aligncenter :text"currentTime"></u--text>…...

机器学习---概率图模型(隐马尔可夫模型、马尔可夫随机场、条件随机场)

1. 隐马尔可夫模型 机器学习最重要的任务是根据已观察到的证据&#xff08;例如训练样本&#xff09;对感兴趣的未知变量&#xff08;例如类别标 记&#xff09;进行估计和推测。概率模型&#xff08;probabilistic model&#xff09;提供了一种描述框架&#xff0c;将描述任…...

cool 框架 node 后端封装三方Api post请求函数

1.需求 现在一些数据源 &#xff0c;需要从三方地址拿到一些数据 比如说电影列表 信息了 影院列表信息了 等一些展示的数据&#xff0c;但是人家这种东西 害需要使用 appkey appserect 这种验签 这种需求 你前端调用接口是直接调用不了的 因为需要用到验签 需要后端接口转接一…...

awd总结

总结&#xff1a; 由于是第一次参加AWD比赛&#xff0c;各方面经验都不足&#xff0c;在参赛的前几天也是疯狂搜集各种脚本、框架、工具等&#xff0c;同时也参考b站的视频进行学习&#xff0c;我发现就是还是实操才能更快的学习 我觉得就是我前期的准备工作不足&#xff0c;…...

【react】react+es6+antd5.13.2+ts,antd表格的操作如何在父组件写?

reactes6antd5.13.2ts,antd表格的操作如何在父组件写&#xff1f; 我的子组件columns.tsx&#xff0c;只加表头&#xff0c;操作放在父组件。 columns.tsx的代码&#xff1a; export const dataColumns [{title: 项目成员,dataIndex: name,key: name,},{title: 可选账号,alig…...

virtio笔记

最近在看虚拟化相关的东西&#xff0c;以virtio-console为例&#xff0c;记录下。 此文只是学习笔记&#xff0c;文中肯定有不少错误&#xff0c;不要参考 devicemd侧&#xff1a; virtio_console.c中&#xff0c;初始化会对port->cb赋值为 viritio_console_control_tx&am…...

初始web服务器(并基于idea来实现无需下载的tomcat)

前言 前面学习了对应的http协议&#xff0c;我们知道了他是在网络层进行数据传输的协议&#xff0c;负责相应数据以及接收数据的规则&#xff0c;但是在人员开发后端的时候不仅仅需要你写io流进行数据传输&#xff0c;还需要你进行对应的tcp协议来进行数据打包发送http协议-CSD…...

软件文档测试

1 文档测试的范围 软件产品由可运行的程序、数据和文档组成。文档是软件的一个重要组成部分。 在软件的整人生命周期中&#xff0c;会用到许多文档&#xff0c;在各个阶段中以文档作为前阶段工作成果的体现和后阶段工作的依据。 软件文档的分类结构图如下图所示&#xff1a; …...

从零开始手写mmo游戏从框架到爆炸(七)— 消息封装

导航&#xff1a;从零开始手写mmo游戏从框架到爆炸&#xff08;零&#xff09;—— 导航-CSDN博客 上一篇&#xff0c;我们初步把消息handler 注册到了服务中&#xff0c;在进行后续工作之前我们需要再做一些准备工作。 第一&#xff1a;把之前自己管理的bean放到spring中…...

从Unity到Three.js(画线组件line)

JavaScript 0基础&#xff0c;只是照着官方文档临摹了下&#xff0c;之后有时间再进行细节学习和功能封装。 import * as THREE from three; //引入threejsconst renderer new THREE.WebGLRenderer();//创建渲染器 //设置渲染范围&#xff0c;当前撑满全屏,屏幕左上角是&…...

LCP 30. 魔塔游戏 - 力扣(LeetCode)

题目描述 小扣当前位于魔塔游戏第一层&#xff0c;共有 N 个房间&#xff0c;编号为 0 ~ N-1。每个房间的补血道具/怪物对于血量影响记于数组 nums&#xff0c;其中正数表示道具补血数值&#xff0c;即血量增加对应数值&#xff1b;负数表示怪物造成伤害值&#xff0c;即血量减…...

用 OpenAI Codex 打造你的 AI 结对编程助手

用 OpenAI Codex 打造你的 AI 结对编程助手 告别重复劳动&#xff0c;让 AI 直接帮你写代码、修 Bug、跑测试 在 AI 编程工具层出不穷的今天&#xff0c;OpenAI Codex 依然是许多开发者心目中的“神器”。与普通的代码补全工具不同&#xff0c;Codex 是一款终端原生的 AI 编程助…...

MATLAB实战:手把手教你实现FM调制解调(附完整代码与避坑指南)

MATLAB实战&#xff1a;从零构建FM通信系统的完整指南 在无线通信领域&#xff0c;频率调制(FM)技术因其出色的抗噪声性能&#xff0c;至今仍广泛应用于广播、对讲机等场景。对于通信工程学生和MATLAB初学者而言&#xff0c;亲手实现一个完整的FM调制解调系统&#xff0c;是理解…...

掌握Nemo文件管理器:Cinnamon桌面环境的高效文件管理利器

掌握Nemo文件管理器&#xff1a;Cinnamon桌面环境的高效文件管理利器 【免费下载链接】nemo File browser for Cinnamon 项目地址: https://gitcode.com/gh_mirrors/ne/nemo Nemo作为Cinnamon桌面环境的默认文件管理器&#xff0c;不仅仅是一个简单的文件浏览器&#xf…...

深度解析PDFMathTranslate:揭秘AI如何实现毫秒级学术文档翻译与精准排版保留

深度解析PDFMathTranslate&#xff1a;揭秘AI如何实现毫秒级学术文档翻译与精准排版保留 【免费下载链接】PDFMathTranslate PDF scientific paper translation with preserved formats - 基于 AI 完整保留排版的 PDF 文档全文双语翻译&#xff0c;支持 Google/DeepL/Ollama/Op…...

4个关键步骤解决Calibre中文路径乱码难题

4个关键步骤解决Calibre中文路径乱码难题 【免费下载链接】calibre-do-not-translate-my-path Switch my calibre library from ascii path to plain Unicode path. 将我的书库从拼音目录切换至非纯英文&#xff08;中文&#xff09;命名 项目地址: https://gitcode.com/gh_m…...

Go语言广播系统设计:基于Channel的高性能事件分发机制

引言 在后端系统架构中&#xff0c;事件广播是一种常见的通信模式。本文将深入分析一个基于Go语言channel实现的广播管理器&#xff0c;探讨其设计思想、实现细节以及在实际项目中的应用价值。 参考代码 点击直达 背景与需求 在许多应用场景中&#xff0c;我们需要实现一对…...

SVGnest智能排版优化器:5分钟掌握材料利用率翻倍的终极技巧

SVGnest智能排版优化器&#xff1a;5分钟掌握材料利用率翻倍的终极技巧 【免费下载链接】SVGnest An open source vector nesting tool 项目地址: https://gitcode.com/gh_mirrors/sv/SVGnest 想象一下&#xff0c;您是否经常在激光切割、CNC加工或3D打印中面临材料浪费…...

基于设备树与内核中断的125KHZ RFID曼彻斯特码实时解码实践

1. 曼彻斯特码解码原理详解 125KHz RFID系统广泛用于门禁、物流追踪等场景&#xff0c;其数据传输采用曼彻斯特编码方式。这种编码最大的特点是每个数据位都包含电平跳变&#xff0c;使得时钟恢复变得简单。具体来说&#xff0c;EM4100卡片每传送一位数据需要64个载波周期&…...

QLVideo终极指南:让macOS Finder完美预览所有视频格式

QLVideo终极指南&#xff1a;让macOS Finder完美预览所有视频格式 【免费下载链接】QuickLookVideo This package allows macOS Finder to display thumbnails, static QuickLook previews, cover art and metadata for most types of video files. 项目地址: https://gitcod…...

tmux快速上手指南:3个核心命令与1个关键快捷键解析

1. 为什么你需要tmux&#xff1f; 如果你经常在服务器上工作&#xff0c;肯定遇到过这样的场景&#xff1a;正在跑一个耗时很长的任务&#xff0c;突然网络波动导致SSH连接断开&#xff0c;所有进程都被终止&#xff0c;几个小时的成果瞬间消失。这种时候&#xff0c;tmux就是你…...