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

React源码解析18(10)------ 实现多节点的Diff算法

摘要

在上一篇中,实现了多节点的渲染。但是之前写得diff算法,只能适用于单节点的情况,例如这种情况:

<div><p><span></span></p>
</div>

如果对于多节点的情况:

<ul><li></li><li></li><li></li>
</ul>

之前实现的diff算法就不会有效果了,所以在这一篇中,我们主要实现针对于多节点的diff算法。

实现之前,我们先将index.js修改一下:

function App() {const [num, setNum] = useState(100)const click1 = () => {console.log(num);setNum(num + 1)}return num % 2 > 0 ? jsx("ul", {onClick: click1,key: 'ul',children: [jsx("li", {children: "1",key: "1"}), jsx("li", {children: "2",key: "2"}), jsx("li", {children: "3",key: "3"})]}): jsx("ul", {onClick: click1,key: 'ul',children: [jsx("li", {children: "2",key: "2"}), jsx("li", {children: "1",key: "1"}), jsx("li", {children: "3",key: "3"})]});
}ReactDOM.createRoot(root).render(<App />)

1.修改beginWork流程

在reconcileChildren方法里面,我们判断了如果element为数组的情况,就是多节点。所以我们需要在这里进行diff算法的处理。

function reconcileChildren(parent,element) {//其他代码。。。。}else if(Array.isArray(element) && element.length > 0) {const newChild = diffReconcileManyChildren(parent, element);if(newChild) {return newChild}//其他代码。。。。

所以我们的diff算法那主要是在diffReconcileManyChildren方法里面实现。

对于多节点的Diff,我们需要进行以下步骤。

  1. 创建变量lastIndex,用来标记索引
  2. 将旧的filberNode列表,转换为map结构,key为filberNode的key,value为filberNode
  3. 遍历新的element数组。
  4. 如果element.key可以在map中找到,lastIndex记录为找到的filberNode的index
  5. 如果找不到,创建新的FilberNode
  6. 继续遍历,如果又在map中找到filberNode,比较fiberNode的index和lastIndex.
  7. 如果index < lastIndex,给filberNode打上移动的标志

基于上面的步骤,实现diffReconcileManyChildren方法

function diffReconcileManyChildren(filberNode, element) {let firstChild = filberNode.child;if(!firstChild) {return;}const head = {sibling: null};const oldChildren = []while(firstChild) {oldChildren.push(firstChild);firstChild = firstChild.sibling;}const oldMap = new Map();oldChildren.forEach((item,index) => {item.index = indexif(item.key) {oldMap.set(item.key, item)}else{oldMap.set(index, item)}})let lastIndex = 0;let empty = headfor(let i=0; i<element.length; i++) {if(!element[i].key){continue;}const useFilber = oldMap.get(element[i].key);useFilber.sibling = null;if(useFilber) {if(useFilber.index < lastIndex) {useFilber.flags = 'insert'}useFilber.memoizedProps = element[i]lastIndex = useFilber.index;empty.sibling = useFilber;empty = empty.sibling;oldMap.delete(element[i].key)}else{const filberNode = new FilberNode(HostComponent, element[i].props, element[i].key) filberNode.type = element[i].typeempty.sibling = filberNode;empty = empty.sibling;}}return head.sibling;
}

经过上面的处理,beginWork流程结束,可复用的filberNode就不会重复创建。

2.修改completeWork流程

在beginWork中,可复用的节点已经被打上了insert的标志,所以在updateCompleteHsotComponent中,我们要判断是不是insert的标志,如果是,就不能无脑创建,而是通过移动DOM的位置来复用DOM。

同时,也要对同级的sibling进行递归处理。

function updateCompleteHostComponent(filberNode) {//其他代码。。。。if(element.key === filberNode.key && element.type === filberNode.type) {addPropsToDOM(filberNode.stateNode, filberNode.pendingProps);if(filberNode.flags === 'insert') {const parent = filberNode.return;parent.stateNode.insertBefore(filberNode.stateNode, filberNode.sibling?.stateNode)}//其他代码if(filberNode.sibling) {completeWork(filberNode.sibling)}
}

在对HostText的处理中,也要考虑,当前的操作是更新还是替换。

function completeHostText(filberNode) {//其他代码。。。。。if(parent && parent.stateNode && parent.tag === HostComponent) {if(!parent.stateNode) {parent.stateNode.appendChild(element);}else{parent.stateNode.replaceChildren(element);}}//其他代码。。。。
}

相关文章:

React源码解析18(10)------ 实现多节点的Diff算法

摘要 在上一篇中&#xff0c;实现了多节点的渲染。但是之前写得diff算法&#xff0c;只能适用于单节点的情况&#xff0c;例如这种情况&#xff1a; <div><p><span></span></p> </div>如果对于多节点的情况&#xff1a; <ul><…...

Linux指令篇!

Linux 是一个广泛使用的开源操作系统&#xff0c;以下是一些常用的 Linux 知识点和指令&#xff1a; 1. 文件和目录操作&#xff1a; - ls&#xff1a;列出目录内容 - cd&#xff1a;切换目录 - pwd&#xff1a;显示当前工作目录 - mkdir&#xff1a;创建目录 - touch…...

Vue2学习笔记のVue组件化编程

目录 Vue组件化编程非单文件组件基本使用几个注意点组件的嵌套VueComponent一个重要的内置关系 单文件组件index.htmlmain.jsApp.vueSchool.vueStudent.vue 各位小伙伴们好呀&#xff0c;不知道上一篇文章你是否有收获&#xff01;这篇是Vue2学习笔记第二篇&#xff0c;也是Vue…...

跨境电商儿童沙画办理EN71测试标准

儿童沙画就是小孩子玩的那种用彩色沙子或者彩色墨水&#xff0c;在有图形轮廓的纸片上去绘画&#xff0c;可以按照儿童沙画底板上的人物轮廓线条&#xff0c;动物线条&#xff0c;风景线条&#xff0c;动漫线条&#xff0c;去添加自己喜欢的颜色&#xff0c;让单调的线条变成自…...

chrome浏览器账号密码输入框自动填充时背景色不变

处理前 使用延时的方式解决 .login-box input,password:-webkit-autofill .login-box input,password:-webkit-autofill:hover, .login-box input,password:-webkit-autofill:focus, .login-box input,password:-webkit-autofill:active {-webkit-transition-delay: 999999…...

【ARM】Day9 cortex-A7核I2C实验(采集温湿度)

1. 2、编写IIC协议&#xff0c;采集温湿度值 iic.h #ifndef __IIC_H__ #define __IIC_H__ #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h" #include "led.h" /* 通过程序模拟实现I2C总线的时序和协议* GPIOF ---> AHB4* I2C1_S…...

【Leetcode】移动零

移动零 题目描述算法描述编程代码 链接: 移动零 题目描述 算法描述 编程代码 class Solution { public:void moveZeroes(vector<int>& nums) {//题目要求不可以复制数组&#xff0c;开辟额外空间int dest -1,curr 0;for(;curr < nums.size();curr){if(nums[cu…...

数据结构入门 — 顺序表详解

前言 数据结构入门 — 顺序表详解 博客主页链接&#xff1a;https://blog.csdn.net/m0_74014525 关注博主&#xff0c;后期持续更新系列文章 文章末尾有源码 *****感谢观看&#xff0c;希望对你有所帮助***** 文章目录 前言一、顺序表1. 顺序表是什么2. 优缺点 二、概念及结构…...

SimpleCG绘图函数(9)--绘制各种线条

一、所有线段函数概述 可填充图形绘制函数都介绍完了&#xff0c;还有一些特殊线条的绘制将在本篇进行讲解。所有特殊线条函数如下所示&#xff0c;其中还有一个区域填充函数floodfill比较特殊&#xff0c;是配合线条函数使用的&#xff1a; //绘制一系列折线段 //折线段以一组…...

RISCV 6 RISC-V加载存储指令

RISCV 6 RISC-V加载存储指令 1 RV32I Load and Store Instructions1.1 LOAD instructions1.1.1 加载指令的指令格式1.1.2 加载指令在使用时需要注意的点 1.2 STORE instructions1.2.1 存储指令的指令格式1.2.2 存储指令在使用时需要注意的点 2 RV64 Load and Store Instruction…...

木叶飞舞之【机器人ROS2】篇章_第二节、turtlebot3安装

没有真实小车的情况下&#xff0c;利用gazebo的仿真&#xff0c;操作小乌龟来学习ros2。废话不多说&#xff0c;直接上命令。 Install Gazebo sudo apt install ros-humble-gazebo-*Install Cartographer 假如前一节未安装源码版本的cartographer&#xff0c;那就安装apt版本…...

【论文阅读】自动驾驶安全的研究现状与挑战

文章目录 摘要1.引言1.1.自动驾驶安全1.2.攻击面1.3.内容和路线图 2.自动驾驶技术2.1.组成2.2.技术 3.传感器安全3.1.照相机3.2.GNSS&#xff08;全球导航系统&#xff09;/IMU&#xff08;惯性测量单元&#xff09;3.3.超声波传感器3.4.毫米波雷达3.5.激光雷达3.6.多传感器交叉…...

标签打印小工具 选择图片打印,按实际尺寸打印。可旋转图片

您可以尝试使用以下标签打印工具&#xff1a; 柯尼卡美能达标签打印机&#xff1a;功能齐全、易于使用的打印机&#xff0c;支持各种标签尺寸和类型。 赛门铁克标签打印机&#xff1a;高速打印、可靠性强的打印机&#xff0c;支持多种操作系统和软件。 齐柏林标签打印机&…...

什么是深拷贝和浅拷贝?

面试回答 在计算机内存中&#xff0c;每个对象都有一个地址&#xff0c;这个地址指向对象在内存中存储的位置。当我们使用变量引用一个对象时&#xff0c;实际上是将该对象的地址赋值给变量。因此&#xff0c;如果我们将一个对象复制到另一个变量中国&#xff0c;实际上是将对象…...

安装docker服务及docker基本操作

一、docker安装&#xff08;yum安装&#xff09; 基于centos7 1.添加docker-ce 源信息 安装依赖包&#xff08;yum-utils 提供了 yum-config-manager &#xff0c;并且 device mapper 存储驱动程序需要device-mapper-persistent-data 和 lvm2&#xff09; yum install yum-…...

【项目经验】:项目中下拉框数据太多造成页面卡顿(二)

一.项目需求 下拉框下拉列表数据是由后端返回的&#xff0c;而且他会变化&#xff0c;所以数据不是写死的而且数据量大。上一篇博客http://t.csdn.cn/sSNTa我们是用的数据懒加载的方式&#xff0c;这次我们使用远程搜索的方式解决这个问题。 二.用到的组件方法介绍 filterabl…...

Prompt本质解密及Evaluation实战(一)

一、基于evaluation的prompt使用解析 基于大模型的应用评估与传统应用程序的评估不太一样&#xff0c;特别是基于GPT系列或者生成式语言模型&#xff0c;因为模型生成的内容与传统意义上所说的内容或者标签不太一样。 以下是借用了ChatGPT官方的evaluation指南提出的对结果的具…...

linux 在系统已有python2版本下安装python3

方法一&#xff1a;使用包管理器安装 更新包索引&#xff1a; sudo apt update 安装Python3&#xff1a; sudo apt install python3 安装Python3的pip&#xff08;如果你需要&#xff09;&#xff1a; sudo apt install python3-pip 验证Python 2和3的安装&#xff1a; pyt…...

IO多路转接 ——— select、poll、epoll

select初识 select是系统提供的一个多路转接接口。 select系统调用可以让我们的程序同时监视多个文件描述符的上的事件是否就绪。 select的核心工作就是等&#xff0c;当监视的多个文件描述符中有一个或多个事件就绪时&#xff0c;select才会成功返回并将对应文件描述符的就绪…...

FPGA原理与结构——FIFO IP核原理学习

一、FIFO概述 1、FIFO的定义 FIFO是英文First-In-First-Out的缩写&#xff0c;是一种先入先出的数据缓冲器&#xff0c;与一般的存储器的区别在于没有地址线&#xff0c; 使用起来简单&#xff0c;缺点是只能顺序读写数据&#xff0c;其数据地址由内部读写指针自动加1完成&…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!

目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...