React diff

120 阅读2分钟

diff算法原理 diff算法发生在beginWork流程中,会根据最新的React element和current Fiber树来生成workInProgres。

  1. 只对同层的元素进行diff
  2. 如果元素从 div 变为 p,那么直接销毁 div 元素,创建 p 元素
  3. 相同的 key 会进行比较

针对 newChild 类型为object, number,string 的元素

  1. 遍历寻找当前current Fiber,
  2. 判断key是否相同,如果不设置 key,默认为 null。如果 key 相同,type 相同,则代表可以复用。
  3. 如果key相同,type不同,将当前 current Fiber 节点以及兄弟节点都删除
  4. 如果key不同,删除当前子节点,继续判断后续的节点。

多节点 diff

如果解析后的jsx对象不是单节点的,而是多节点的。(处理完之后是一个数组) 前置准备:

  1. 将current Fiber的key,value 映射为 map
  2. 准备一个"指向最后一个元素的指针" LastPlacedIndex
  3. 指向 current Fiber 的头节点指针
  4. 指向newChild 第一个索引的索引。

第一次循环

  1. 根据 索引指向的当前 newChild 判断当前 current Fiber 树中是否有元素可以复用
    1. 如果key相同 type 相同可以复用
  2. 如果key不同,跳出循环,第一轮遍历结束。
  3. 如果type 不同,代表当前节点不可复用,打上删除标记,继续循环。 此时有以下几种情况
  4. 如果current Fiber中还存在元素,将current Fiber中存在的元素打上删除标记
  5. 如果 new Child 中还存在元素,将newChild 中的元素创建为 fiber 节点。
  6. 如果current Fiber 和newChild 都存在元素,进行下一轮循环

第二次循环

  1. 继续索引newChild 剩下的元素,同时通过 key以及生成的 map 来判断是否有复用的元素。
    1. 如果 key 一样,且 type 一样,说明可以复用。此时需要判断 此复用节点在 currentFiber 中的原始索引,如果原始索引小于 lanIndex,打移动的标记。
    2. 如果原始索引大于 lanIndex,将 lanIndex 的值置为该索引值。
  2. 全部走完 newChild 之后,在 commit 会对currentFiber 中的标记进行对应的处理。