Reconclier

调合分为两个步骤,递与归,在递阶段首次挂载时会创建整个应用的fiber链表树,在更新时会对比currentworkInprogress指针指向的两棵树,在更新时就包括diff。 在归阶段为fiberNode打上对应的tag,在commit阶段会被执行本次需要的操作。

beginWork

主要是创建fiber链表。
根据current指针是否为空来判断时首次挂载还是更新
在首次挂载时会从根节点开始,向下进行深度优先遍历,为遍历到的每一个jsx对象创建对象的fiber链表
在每次遍历到叶子节点child属性为空时会执行completeWork, 对新建的fiber节点处理
在满足didReceiveUpdate = false时, 表示会复用该fiber节点,也就是cloneFiber
begiinWork的函数的目的就是创建fiber链表,并返回下一个工作的子jsx对象。

completeWork

该阶段的主要工作就是创建dom节点, 设置属性, 并在首次挂载每次执行的时候把已经存在的子dom节点加入到dom节点下。创建的dom实例保存在stateNode属性上

Diff

单节点diff

  1. key不同key不同,将该fiber标记为删除,并重新创建一个新的fiber node
  2. key相同 ,type不同,将该fiber及其兄弟fiber标记为删除
  3. key相同,type相同,返回复用的fiber

    多节点diff

    第一轮遍历

  4. 遍历newChildren,将newChildren[i]与oldFiber比较,判断DOM节点是否可复用。如果可复用,i++,继续比较newChildren[i]与oldFiber.sibling,可以复用则继续遍历。

  5. 如果不可复用,分两种情况:
  • key不同导致不可复用,立即跳出整个遍历,第一轮遍历结束。
  • key相同type不同导致不可复用,会将oldFiber标记为DELETION,并继续遍历
  1. 如果newChildren遍历完(即i === newChildren.length - 1)或者oldFiber遍历完(即oldFiber.sibling === null),跳出遍历,第一轮遍历结束。

    第二轮遍历

  2. newChildren与oldFiber同时遍历完此时diff结束、

  3. newCHilren没有遍历完成,oldFiber完了,表示新增的打上Placement标记newChildren遍历完成
  4. oldFiber没有,表示删除打上Deletion标记
  5. 二者都没遍历完成,表示移动,终止本次循环

    第三轮遍历

    用变量lastPlacedIndex表示最后一个可复用的节点在oldFiber中的位置索引
    如果oldIndex < lastPlacedIndex,代表本次更新该节点需要向右移动。
    lastPlacedIndex初始为0,每遍历一个可复用的节点,如果oldIndex >= lastPlacedIndex,则lastPlacedIndex = oldIndex。

    commit阶段

    将变化更新到页面的过程

    before mutation

    保存优先级,以同步的优先级,执行完毕后再恢复到之前的优先级

处理focus相关
commitBeforeMutationEffects 来处理effectList
commitBeforeMutationEffects

  • 处理DOM节点渲染/删除后的焦点失去和获取
  • 调用getSnapshotBeforeUpdate生命周期函数
  • 调度useEffect

    mutation

    遍历effectList, 根据effectTag执行增删改。 在这里执行的是commitMutationEffects
    commitMutationEffects

  • 重置文本节点

  • 更新ref对象
  • 根据effectTag处理插入、更新、删除、插入并更新等dom操作
  • 更新时调用useLayoutEffect的销毁函数

    layout

    调用 commitLayoutEffects函数,遍历执行effectList
    调用变更之后的同步回调函数,比如setState的第二个参数,useLayoutEffectdidMount
    赋值ref对象
  • 对于类组件,根据current === null 来区分是挂载还是更新调用didMount、didUpdate. 对于setState的第二个参数,也是在此时调用
  • 函数组件,调用layoutEffect的回调函数