React render理解

126 阅读2分钟

render

在react项目中我们经常会见到类似下面的代码

ReactDOM.render(<APP/>,document.getElementById('root'));

从这段代码中我们可以看出 React 应用会在容器root上渲染出一个组件 这也是React的入口代码。接下来就来详细剖析render的流程。

首先

render阶段开始于 performSyncWorkOnRoot 或者 performConcurrentWorkOnRoot方法的调用。这取决于本次更新是同步更新还是异步更新。 但目前我们不需要掌握这两种方法,只需要知道在这两个方法中会调用如下两个方法。

// performSyncWorkOnRoot会调用该方法 
function workLoopSync( ) {
 while(workInProgress !== null) {
  performUnitOfWork(workInProgress); 
 } 
}

// performConcurrentWorkOnRoot会调用该方法
function workLoopConcurrent( ) {
 while(workInProgress !== null&& !shouldYield{
  performUnitOfWork(workInProgress);
 }
}

在这个代码块中可以看到,他们的区别是 是否调用shouldYield。如果当前浏览器帧没有剩余时间,shouldYield会中止循环,知道浏览器有空闲时间后再继续遍历。

workInProgress 代表当前已创建的 workInProgress fiber 。

performUnitOfWork 方法会创建下一个 Fiber节点 并赋值给 workInProgress ,并将 workInProgress 与已创建的 Fiber节点 连接起来构成 Fiber树。

在其中 会分别创建两个root,一个 root 叫做 FiberRoot,另一个 root 叫做 RootFiber,并且它们两者还是相互引用的。

对于 FiberRoot 对象来说,我们现在只需要了解两个属性,分别是 containerInfo 及 current。前者代表着容器信息,也就是我们的 document.querySelector('#root');后者指向 RootFiber

我们知道Fiber Reconciler 是从 Stack Reconciler 重构而来,通过遍历的方式实现可中断的递归,所以performUnitOfWork 的工作可以分为两部分:“递”和“归”。

“递”阶段

首先从 rootFiber 开始向下深度优先遍历。为遍历到的每个 Fiber节点 调用beginWork方法 。

该方法会根据传入的 Fiber节点 创建 子Fiber节点 ,并将这两个 Fiber节点 连接起来。

当遍历到叶子节点(即没有子组件的组件)时就会进入“归”阶段。

“归”阶段

在“归”阶段会调用completeWork处理Fiber节点。 当某个Fiber节点 执行完completeWork,如果存在 兄弟Fiber节点 (也就是 fiber.sibling!==null),会进入兄弟Fiber的“递”阶段。 如果不存在 兄弟Fiber节点,会进入父级Fiber的“归”阶段。

在此,借用网上的一张图 来 直观的理解一下

src=http___www.zyiz.net_upload_202004_20_202004201118136701.png&refer=http___www.zyiz.jpg

“递”和“归”阶段会交替进行知道“归”到rootFiber。到此,render阶段的工作就结束了。