返回
如何让改变源于趣味:渲染器的核心 Diff 算法2
前端
2023-09-15 08:24:05
在上一小节中,我们尝试拿着新 children 中的第一个节点去旧 children 中寻找与之拥有相同 key 值的可复用节点,然后并非总是能够找得到,当新的 children 中拥有全新节点时,旧的 children 中就必然没有与之对应的节点,此时就需要新增一个节点到真实 DOM 中。
新增节点最常见的一种情况就是新 children 是一个完全全新的数组。我们已经知道当新旧 children 都不为空时,新的 children 中的第一个节点,如果在旧的 children 中能够找到拥有相同 key 值的节点,那么就复用该节点;如果没有找到,就新增一个新节点。现在我们把新 children 改成一个空数组,即没有任何节点,那么对于每一个新 children,我们都找不到拥有相同 key 值的旧节点,因此都需要新增节点。
为了更直观地了解这个过程,我们可以借助一个简单的示例。假设我们有一个组件,它的 render 方法返回一个包含三个元素的数组:
render() {
return [
<div key="A">A</div>,
<div key="B">B</div>,
<div key="C">C</div>
];
}
如果我们首次渲染这个组件,那么渲染器会创建一个包含三个 div 元素的真实 DOM:
<div key="A">A</div>
<div key="B">B</div>
<div key="C">C</div>
现在,假设我们修改了这个组件的 render 方法,使其返回一个包含四个元素的数组:
render() {
return [
<div key="A">A</div>,
<div key="B">B</div>,
<div key="C">C</div>,
<div key="D">D</div>
];
}
当渲染器再次渲染这个组件时,它会发现新 children 中多了第四个节点,即拥有 key 值为 "D" 的 div 元素。由于旧 children 中没有拥有相同 key 值的节点,因此渲染器会为这个新节点创建一个新的 div 元素并添加到真实 DOM 中:
<div key="A">A</div>
<div key="B">B</div>
<div key="C">C</div>
<div key="D">D</div>
这个过程就是 Diff 算法中关于新元素的处理过程。渲染器会根据新旧 children 的差异,决定是复用节点还是新增节点,从而确保真实 DOM 与虚拟 DOM 保持一致。