react源码系列之一、render阶段

184 阅读2分钟

整体流程概览

src/index.js --> ReactDOM.render --> 初始化应用并创建整个应用的根节点fiberRootNode,而每次调用render都会创建新的当前fiber树的根节点rootFiber --> performSyncWorkOnRoot(开始进入render阶段) --> commitRoot(进入commit阶段) render阶段开始于performSyncWorkOnRoot或performConcurrentWorkOnRoot方法的调用。这取决于本次更新是同步更新还是异步更新。

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

每次render阶段都会遍历整颗fiber树,循环调用performUnitOfWork直到workInProgress为null,首屏渲染时会调用createWorkInProgress生成第一个workInProgress,后续在completeUnitOfWork中会赋值workInProgress = completedWork生成下一个workInProgress;更新时会判断是否命中优化来选择不同逻辑。 image.png

render阶段概览

  • 递阶段:从rootFiber开始向下深度优先遍历。为遍历到的每个fiber节点调用beginWork,该方法作用是根据传入的fiber节点创建子fiber,并连接这两个fiber,当没有子组件时就进入归阶段;
  • 归阶段:调用completeWork处理fiber,当某个fiber执行完completeWork时,如果其存在兄弟fiber(fiber.sibling !== null),则进入兄弟节点执行beginWork,否则会进入父级fiber的completeWork,一直归到rootFiber则render阶段完成。
  • 例子:
function App() {
  return (
    <div>
      i am
      <span>weison</span>
    </div>
  )
}

以上在render阶段会一次执行:

  1. rootFiber beginWork
  • 首次进入的是当前fiber树的根节点rootFiber,对应tag为3,首屏渲染时也只有这个的current !== null

image.png 2. App Fiber beginWork 3. div Fiber beginWork 4. "i am" Fiber beginWork 5. "i am" Fiber completeWork 6. span Fiber beginWork

  • (单一文本子节点的fiber,react做了优化处理,不会进入weison的beginWork)
  1. span Fiber completeWork
  2. div Fiber completeWork
  3. App Fiber completeWork
  4. rootFiber completeWork

beginWork细节

image.png

completeWork细节

image.png

render阶段完整流程图及双缓存架构原理图

React源码流程图.drawio.png