当前位置: 首页 > 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完成&…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

MySQL的pymysql操作

本章是MySQL的最后一章&#xff0c;MySQL到此完结&#xff0c;下一站Hadoop&#xff01;&#xff01;&#xff01; 这章很简单&#xff0c;完整代码在最后&#xff0c;详细讲解之前python课程里面也有&#xff0c;感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...