diff算法原理 diff算法发生在beginWork流程中,会根据最新的React element和current Fiber树来生成workInProgres。
- 只对同层的元素进行diff
- 如果元素从 div 变为 p,那么直接销毁 div 元素,创建 p 元素
- 相同的 key 会进行比较
针对 newChild 类型为object, number,string 的元素
- 遍历寻找当前current Fiber,
- 判断key是否相同,如果不设置 key,默认为 null。如果 key 相同,type 相同,则代表可以复用。
- 如果key相同,type不同,将当前 current Fiber 节点以及兄弟节点都删除
- 如果key不同,删除当前子节点,继续判断后续的节点。
多节点 diff
如果解析后的jsx对象不是单节点的,而是多节点的。(处理完之后是一个数组) 前置准备:
- 将current Fiber的key,value 映射为 map
- 准备一个"指向最后一个元素的指针" LastPlacedIndex
- 指向 current Fiber 的头节点指针
- 指向newChild 第一个索引的索引。
第一次循环
- 根据 索引指向的当前 newChild 判断当前 current Fiber 树中是否有元素可以复用
- 如果key相同 type 相同可以复用
- 如果key不同,跳出循环,第一轮遍历结束。
- 如果type 不同,代表当前节点不可复用,打上删除标记,继续循环。 此时有以下几种情况
- 如果current Fiber中还存在元素,将current Fiber中存在的元素打上删除标记
- 如果 new Child 中还存在元素,将newChild 中的元素创建为 fiber 节点。
- 如果current Fiber 和newChild 都存在元素,进行下一轮循环
第二次循环
- 继续索引newChild 剩下的元素,同时通过 key以及生成的 map 来判断是否有复用的元素。
- 如果 key 一样,且 type 一样,说明可以复用。此时需要判断 此复用节点在 currentFiber 中的原始索引,如果原始索引小于 lanIndex,打移动的标记。
- 如果原始索引大于 lanIndex,将 lanIndex 的值置为该索引值。
- 全部走完 newChild 之后,在 commit 会对currentFiber 中的标记进行对应的处理。