render阶段:
总的调用的函数顺序:
- performSyncWorkOnRoot / performConcurrentWorkOnRoot
- renderRootSync / renderRootConcurrent
- workLoopSync / workLoopConcurrent
- performUnitOfWork
- beginWork / completeUnitOfWork
- 根据 workInProgress.tag调用不同的构建fiber方法
- reconcileChildren
- 根据 current === null 来判断挂载还是更新
- mountChildFibers / reconcileChildFiber
1. performSyncWorkOnRoot 或者 performConcurrentWorkOnRoot调用
(区别:本次更新是否同步异步)
-
performUnitOfWork: 创建fiber节点,并将workInProgress 与创建的新节点构成节点树,具体怎么创建的呢?
-
performUnitOfWork 分两个阶段:
一,递阶段 --- beginWork;
二,归阶段 ---- completeWork。
这2阶段又分mount和update情况,主要通过 current === null 判断。
递阶段:beginWork负责深度遍历fiber节点,并为其创建子fiber节点,直到遇到叶子节点,则开始归阶段。
归阶段: 有兄弟节点,则执行兄弟节点的‘递’阶段,如果没有兄弟阶段,则执行父节点的的‘归阶段’,直到rootFiber。
-
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节点并且返回。
-
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阶段:
-
会根据调用 prepareUpdate ---> diffProperties 的函数,返回一个更新任务的数组: 该数组第 i 项为要改动的key ,第i + 1项是 key 对应的值。
-
然后该数组会存在workInProgress.updateQueue 中。
-
有改动的话 调用 markUpdate: workInProgress.flags |= Update; 打上标签
- 在completeWork 上层会执行会组成一个 有改动的链表。在commit阶段直接使用,不用再从头不遍历fiber节点。
beginWork流程图:
compeletWork流程图: