当前位置: 首页 > 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);}}//其他代码。。。。
}
http://www.lryc.cn/news/137039.html

相关文章:

  • Linux指令篇!
  • Vue2学习笔记のVue组件化编程
  • 跨境电商儿童沙画办理EN71测试标准
  • chrome浏览器账号密码输入框自动填充时背景色不变
  • 【ARM】Day9 cortex-A7核I2C实验(采集温湿度)
  • 【Leetcode】移动零
  • 数据结构入门 — 顺序表详解
  • SimpleCG绘图函数(9)--绘制各种线条
  • RISCV 6 RISC-V加载存储指令
  • 木叶飞舞之【机器人ROS2】篇章_第二节、turtlebot3安装
  • 【论文阅读】自动驾驶安全的研究现状与挑战
  • 标签打印小工具 选择图片打印,按实际尺寸打印。可旋转图片
  • 什么是深拷贝和浅拷贝?
  • 安装docker服务及docker基本操作
  • 【项目经验】:项目中下拉框数据太多造成页面卡顿(二)
  • Prompt本质解密及Evaluation实战(一)
  • linux 在系统已有python2版本下安装python3
  • IO多路转接 ——— select、poll、epoll
  • FPGA原理与结构——FIFO IP核原理学习
  • 【Linux操作系统】Linux中的信号回收:管理子进程的关键步骤
  • Spark大数据分析与实战笔记(第一章 Scala语言基础-1)
  • R语言03-R语言中的矩阵
  • “深入理解JVM:探索Java虚拟机的工作原理与优化技巧“
  • SQL注入原理
  • PIL.Image和base64,格式互转
  • vue父子组件传值(v-model)
  • Java接口详解
  • Windows共享文件夹,用户密码访问
  • Mac更新node
  • 2023国赛数学建模思路 - 案例:粒子群算法