分为两种:单节点和多节点。这个单节点和多节点是指新生成的 JSX 对象里面的 newChild 是不是数组。
都是比较 newChild 和 currentFiber 生成 workInProgressFiber 的过程。
单节点 diff
以 REACT_ELEMENT_TYPE 为例。
- 如果 key 不同,则将此 fiber 标记为删除;
- 如果 key 相同,再比较 type 是否一致
- 如果 type 一致,则复用此 fiber,然后将 fiber.sibling 之后的所有 fiber 删除
- 如果 type 不一致,则将所有的 fiber 均删除
多点节 diff
更新节点、删除/插入节点、交换节点位置。由于更新的发生的更频繁,所以分为两步走,先处理更新,再处理其他情况。
-
处理更新节点
- 比较 newChildren[i++] 是不是可以复用 currentFiber.sibling
- 如果 key 不同,跳出循环
- 如果 key 相同,比较 type
- 如果 type 相同,复用 currentFiber
- 如果 type 不同,将 currentFiber 标记为删除,将 newChild 创建 fiber 标记为新增
- 比较结束后跳出循环
-
处理剩下不属于更新的节点
- currentFiber 遍历完成,将 newChild 创建 fiber 标记新增
- newChild 遍历完成,currentFiber 标记删除
- 均未遍历完成
- 将 currentFiber 做成一个 {key: fiber} 的 map
- 遍历 newChild 然后判断是不是可以重用以及 placementIndex,重用后从 map 里面删除
- 最后将 map 里面的所有元素都标记为删除