React 源码解析系列 - React 的 render 阶段(一)(基本流程介绍)

React 的工作流程 React 的工作流程主要分为 render 和 commit 两个阶段:

  • render 阶段根据 JSX 转化成的 ReactElement (更准确地来说,jsx 经 babel 转化后是 React.createElement() 的代码段,在 render 阶段该代码段被执行后便生成了对应的 ReactElement 对象)来创建 Fiber 树;React 采用“双缓存”的思想,因此同一时刻维持有两棵 Fiber 树 ,一颗是 current,对应浏览器当前已渲染的 DOM 树,而另一棵则是 workInProgress,是在初始化时或者组件状态更新后由 reconciler 创建的一个工作副本。
  • commit 阶段指的是把 workInProgress 渲染到页面上 ,当然这个过程并不会是全量更新,而是根据创建 workInProgress 时打的一些“标记”(effectTag),来确定在某个 DOM 节点上具体做什么操作,比如更新文本、删除节点等,以尽量小的代价来在 DOM 上还原 workInProgress ;workInProgress 会在 commit 后被置为 current。
render 阶段的入口 render 阶段开始于 performSyncWorkOnRoot 或 performConcurrentWorkOnRoot 方法的调用,这两个方法的差异在于一个是同步,而另一个是异步(concurrent)的。
这两个方法分别会调用下面两个方法—— workLoopSync 和 workLoopConcurrent:
function workLoopSync() { // Already timed out, so perform work without checking if we need to yield. while (workInProgress !== null) { performUnitOfWork(workInProgress); } }function workLoopConcurrent() { // Perform work until Scheduler asks us to yield while (workInProgress !== null && !shouldYield()) { performUnitOfWork(workInProgress); } }

这两个方法的差别在于是否调用 shouldYield() 来判断当前浏览器帧有没有空余时间,对于 concurrent 模式来说,如果没有空余时间就会退出当前循环了;可以看到这两个方法最终都调用了 performUnitOfWork 。
通过方法中的 while 循环,Fiber Reconciler 将完成对虚拟 DOM 的一个深度遍历,以及完成对整棵 workInProgress Fiber Tree 的创建。
performUnitOfWork performUnitOfWork 方法会创建下一个 Fiber 节点 ,并将其与 workInProgress 所指向的 FiberNode 进行连接(workInProgress相当于是当前 FiberTree 上最末的一个 FiberNode,与其相连则表示将新的 FiberNode 挂在 FiberTree 上),完成后将 workInProgress 这 FiberTree 的指针赋值为刚创建的 FiberNode,再进行下一轮的循环。
Fiber Reconciler 由于是从 Stack Reconciler 重构来的,它实际上模拟了“递归”的执行过程,这实际上也是一个类似于“深度优先遍历”的过程。
render 的“递”阶段 —— beginWork
在“递”阶段,调用的是 beginWork 方法,在该方法中会判断当前传入的 Fiber 节点是否有对应的子节点; 如果有子节点的话 就创建子 Fiber 节点并返回,这样在 performUnitOfWork 下一轮的循环中就会继续执行子节点的“递”阶段,否则就执行当前 Fiber 节点的“归”阶段。
render 的“归”阶段 —— completeWork
在“归”阶段,调用的是 completeUnitOfWork 方法;在处理完当前节点(主要是创建当前节点的 DOM ,以及收拢后代节点的 DOM 以及 effectTag)后,该方法会判断当前传入的 Fiber 节点是否有对应的兄弟节点(sibling);如果有兄弟节点的话,则返回兄弟节点,下次循环时将进入兄弟节点的“递”阶段,否则就返回父节点,下次循环时执行父节点的“归”阶段。
const siblingFiber = completedWork.sibling; if (siblingFiber !== null) { // If there is more work to do in this returnFiber, do that next. workInProgress = siblingFiber; return; } // Otherwise, return to the parent completedWork = returnFiber; // Update the next thing we're working on in case something throws. workInProgress = completedWork;

举例说明递归的过程
function App() { return (array huang
) }ReactDom.render(, document.getElementById('#root'));

React 源码解析系列 - React 的 render 阶段(一)(基本流程介绍)
文章图片

1. rootFiber beginWork 2. App Fiber beginWork 3. p Fiber beginWork 4. span Fiber beginWork 5. span Fiber completeWork // 注意这里是直接走到 span 的“归”阶段,因为文本节点 "array" 被优化处理了 6. span Fiber beginWork 7. span Fiber completeWork 8. p Fiber completeWork 9. App Fiber completeWork 10. rootFiber completeWork

流程结尾 【React 源码解析系列 - React 的 render 阶段(一)(基本流程介绍)】至此, render 阶段全部工作完成。在 performSyncWorkOnRoot 函数中 fiberRootNode 被传递给 commitRoot 方法,开启 commit 阶段工作流程。

    推荐阅读