react源码系列 -- render阶段

·  阅读 70

render阶段:

    总的调用的函数顺序:

  • performSyncWorkOnRoot / performConcurrentWorkOnRoot
  • renderRootSync / renderRootConcurrent
  • workLoopSync / workLoopConcurrent
  • performUnitOfWork
  • beginWork / completeUnitOfWork
  • 根据 workInProgress.tag调用不同的构建fiber方法
  • reconcileChildren
  • 根据 current === null 来判断挂载还是更新
  • mountChildFibers / reconcileChildFiber

       

    1. performSyncWorkOnRoot 或者 performConcurrentWorkOnRoot调用

    (区别:本次更新是否同步异步)     

  1. performUnitOfWork: 创建fiber节点,并将workInProgress 与创建的新节点构成节点树,具体怎么创建的呢?

    1. performUnitOfWork 分两个阶段:     

      一,递阶段 --- beginWork;

      二,归阶段 ---- completeWork。

      这2阶段又分mount和update情况,主要通过 current === null 判断。

      递阶段:beginWork负责深度遍历fiber节点,并为其创建子fiber节点,直到遇到叶子节点,则开始归阶段。

      归阶段: 有兄弟节点,则执行兄弟节点的‘递’阶段,如果没有兄弟阶段,则执行父节点的的‘归阶段’,直到rootFiber。

      1. beginWork主要做的事情: beginWork 主要是深度优先的 ‘递’ 构建子fiber节点。

        在mount阶段

        根据tag 进行不同fiber逻辑节点的创建,最终会走reconcileChildren 创建子fiber。

        beginWork函数执行的顺序: (来自performance)     beginWork ---> mountChildFibers (挂载) / reconcileChildFibers(更新生成effectTag)---> mountIndeterminateComponent ---> createChild ---> createFiberFromElement ---> createFiber ---> FiberNode reconcileChildFibers: 生成当前fiber节点的child 的fiber节点

         function FiberNode(tag, pendingProps, key, mode) {
          // Instance
          this.tag = tag;
          this.key = key;
          this.elementType = null;
          this.type = null;
          this.stateNode = null; // Fiber
        
          this.return = null;
          this.child = null;
          this.sibling = null;
          this.index = 0;
          this.ref = null;
          this.pendingProps = pendingProps;
          this.memoizedProps = null;
          this.updateQueue = null;
          this.memoizedState = null;
          this.dependencies = null;
          this.mode = mode; // Effects
        
          this.flags = NoFlags;
          this.subtreeFlags = NoFlags;
          this.deletions = null;
          this.lanes = NoLanes;
          this.childLanes = NoLanes;
          this.alternate = null;
        } 
        复制代码

        在update阶段:     会有一个复用判断,和diff 操作,didReceiveUpdate 表示当前节点有变化。

            第一次更新的时候除了 FiberRootNode.current === rootFiber 以外都没有alternate属性,第二次更新才都有了:

        reconcileChildren是返回当前workInprogress的child的fiber节点。

        完整递更新的流程:1. beginWork 是否存在来current来判断是否进入优化didReceiveUpdate阶段。如果命中,那么会进入bailoutOnAlreadyFinishedWork直接调用createWorkInProgress 创建子fiber节点。如果没有命中最终会走到reconcileChildren:对比新的jsx 和 当前的fiber节点,将对比的结果产生新的fiber节点并且返回。

      2. completeWork主要做的事情:

        在mount阶段

        • Fiber节点生成对应的DOM节点

        • 将子孙DOM节点插入刚生成的DOM节点

        • update逻辑中的updateHostComponent类似的处理props的过程

       // 为`Fiber节点`生成对应的`DOM节点`
       var instance = createInstance(type, newProps, rootContainerInstance, currentHostContext, workInProgress);
       // 将子孙`DOM节点`插入刚生成的`DOM节点`中
       appendAllChildren(instance, workInProgress, false, false);
       workInProgress.stateNode = instance;
       // 处理`props`
       if (finalizeInitialChildren(instance, type, newProps, rootContainerInstance)) {
           markUpdate(workInProgress);
       }
      复制代码

在update阶段:

  1. 会根据调用 prepareUpdate ---> diffProperties 的函数,返回一个更新任务的数组: 该数组第 i 项为要改动的key ,第i + 1项是 key 对应的值。

  2. 然后该数组会存在workInProgress.updateQueue 中。

  3. 有改动的话 调用 markUpdate: workInProgress.flags |= Update; 打上标签

    1. 在completeWork 上层会执行会组成一个 有改动的链表。在commit阶段直接使用,不用再从头不遍历fiber节点。

beginWork流程图:

compeletWork流程图:

分类:
前端
分类:
前端
收藏成功!
已添加到「」, 点击更改