React17中dom-diff

我心飞翔 分类:javascript

React17中的DOM-DIFF算法

React17中的dom-diff是老fiber树跟新jsx的对比,生成新的fiber树的过程

  • 单节点比较
  • 多节点比较

1.单节点比较

如果新的子节点(JSX)只有一个元素的话,老fiber可以是一个或者多个

  • 两个节点相同的条件是typekey都相同
  • 插入:Placement=2
  • 更新:Update=4
  • 插入并更新:PlacementAndUpdate=6
  • 删除:Deletion=8

1.1.一对一,type不同

//老
<div>
    <h1>h1</h1>
</div>

//新
<div>
    <h2>h1</h2>
</div>
 
  • 1.在调和阶段把这个老fiber标记为删除
  • 2.根据新的jsx生成新的fiber节点并标记为插入
  • 3.在提交阶段执行删除h1和添加h2操作

1.2.一对一,key不同

//老
<div>
    <h1 key='h1'>h1</h1>
</div>

//新
<div>
    <h1 key='h2'>h1</h1>
</div>
 
  • 1.在调和阶段把这个老fiber标记为删除
  • 2.根据新的jsx生成新的fiber节点并标记为插入
  • 3.在提交阶段执行删除h1和添加h2操作

1.3.一对一,type&key相同

//老
<div>
    <h1 key='h1'>h1</h1>
</div>

//新
<div>
    <h1 key='h1'>h2</h1>
</div>
 
  • 1.在调和阶段把这个老fiber标记为更新,讲新的属性更新到老的fiber上
  • 2.在提交阶段进行更新

1.4.一对多

//老
<div>
    <h1 key="h1">h1</h1>
	<h2 key="h2">h2</h2>
</div>

//新
<div>
    <h2 key="h2">h2</h2>
</div>
 
  • 将h1标记为删除
  • 将h2标记为更新
  • 提交阶段进行删除,更新

2.多节点

  • 多节点会经历两轮遍历
  • 第一轮遍历主要是处理节点的更新标记,更新包括属性和类型的更新
  • 第二轮遍历主要处理节点的新增,删除和移动标记
  • 移动是遵循尽量少移动,新的地位高的不动,地位低的动

2.1.一一对比,都可复用

//老
<ul>
<li key="A">A</li>
<li key="B">B</li>
<li key="C">C</li>
<li key="D">D</li>
</ul>

//新
<ul>
<li key="A">A-new</li>
<li key="B">B-new</li>
<li key="C">C-new</li>
<li key="D">D-new</li>
</ul>
 
  • 一一对比,全部标记为更新

2.2.一一对比,key相同,type不同

//老
<ul>
<li key="A">A</li>
<li key="B">B</li>
<li key="C">C</li>
<li key="D">D</li>
</ul>

//新
<ul>
<div key="A">A-new</div>
<li key="B">B-new</li>
<li key="C">C-new</li>
<li key="D">D-new</li>
</ul>
 
  • 第一轮对比,key='A'相同,但是type不同,老fiber标记为删除,根据新的jsx生成新的fiber节点
  • 进入第二轮循环,将老的fiber的type和key映射成一个map={B:'li',C:'li',D:'li},进行循环遍历,将剩余的老fiber标记为更新

2.3.多对多,乱序

//老
<ul>
<li key="A">A</li>
<li key="B">B</li>
<li key="C">C</li>
<li key="D">D</li>
<li key="E">E</li>
<li key="F">F</li>
</ul>
//新
<ul>
<li key="A">A-new</li>
<li key="C">C-new</li>
<li key="E">E-new</li>
<li key="B">B-new</li>
<li key="G">G</li>
</ul>
  • 第一轮对比,将fiber A 标记为更新
  • 进入第二轮循环,将老的fiber的type和key映射成一个map={B:'li',C:'li',D:'li',E:'li',F:'li},进行循环遍历,标记可以复用,删除,移动

React17中dom-diff

回复

我来回复
  • 暂无回复内容