美文网首页
react17源码解读-render阶段

react17源码解读-render阶段

作者: Mr无愧于心 | 来源:发表于2022-02-22 17:04 被阅读0次

render阶段开始于performSyncWorkOnRoot或performConcurrntWorkOnRoot方法的调用。

两个的区别是是否调用了shouldYield。如果浏览器没有剩余时间shouldYield会终止循环,直到浏览器有空闲时间后再继续遍历。

function workLoopConcurrent() {
  while (workInProgress !== null && !shouldYield()) {
    performUnitOfWork(workInProgress);
  }
}

// workInProgress代表当前以创建的workInProgress fiber
// performUnitOfWork方法会创建下一个fiber并赋值给workInProgress,并将workInProgress与已经创建的fiber节点连接起来构成Fiber树

节点遍历的方式实现可中断的递归

  • 递 beginWork
    从rootFiber开始深度优先遍历。为遍历到的每个fiber节点调用beginWork
    beginWork的执行流程
function beginWork(
  current: Fiber | null,// 当前组件对应的fiber节点在上一次更新时的fiber节点:workInProgress.alternate
  workInProgress: Fiber,// 当前组件对应的fiber节点
  renderLanes: Lanes,// 优先级相关
): Fiber | null {
  if(current!==null){
    // update阶段,根据diff复用fiber节点
  }else{
    // mount阶段,fiber.tag的不同,创建不同类型的子fiber
  }
}

如果在组件的mount阶段,是首次渲染,此时current==null,update阶段current!==null(后续将current==null作为判断组件是mount还是update阶段的依据)。beginWork可以分为两部分,update时,在满足一定条件下可以复用current节点(diff),mount时,根据fiber.tag的不同,创建不同类型的子fiber。
diff阶段要知道增删改查的dom操作,具体的操作类型保存在fiber的effectTag中(placement\update\placementAndUpdate\deletion)

  • 归 completeWork
    当某个fiber节点执行完completeWork,如果其存在兄弟fiber节点,会进入兄弟fiber的“递”阶段,如果不存在兄弟节点就会进入父fiber的“归”阶段。
    completeWork的执行流程
function completeWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderLanes: Lanes,
): Fiber | null {
  const newProps = workInProgress.pendingProps;

  switch (workInProgress.tag) {
    case IndeterminateComponent:
    case LazyComponent:
    case SimpleMemoComponent:
    case FunctionComponent:
    case ForwardRef:
    case Fragment:
    case Mode:
    case Profiler:
    case ContextConsumer:
    case MemoComponent:
      return null;
    case ClassComponent: {
      // ...省略
      return null;
    }
    case HostRoot: {
      // ...省略
      updateHostContainer(workInProgress);
      return null;
    }
    case HostComponent: {
      // ...省略
      return null;
    }

“归”阶段和beginwork一样根据current===null判断是mount还是update,根据不同的workInProgress.tag作出不同的处理。
update时,fiber已经存在dom节点,不需要生成dom,需要做的是处理props,如事件、样式等。被处理完的props会被赋值给workInProgress.updateQueue,并最终在commit阶段被渲染到页面上。mount时,会为fiber节点生成对应的dom节点,将子孙的dom节点插入到刚生成的dom节点中,和与update阶段类似的处理props逻辑。

  • effectList
    在completeWork的上层函数completeUnitOfWork中,每个执行完completeWork且存在effectTag的fiber节点会被保存在effectList单向链表中。
    effectList中第一个fiber节点保存在fiber.firstEffect,最后一个元素保存在lastEffect中。
                         nextEffect               nextEffect
rootFiber.firstEffect------------------->fiber------------------->fiber
// 这样只要在commit阶段遍历effectList就能执行所有effect了

“递”和“归”阶段交错之心直到“归”到rootFiber,render的工作就结束了。在performSyncWorkOnRoot函数中fiberRootNood被传递给commitRoot,开启commit阶段流程。

相关文章

网友评论

      本文标题:react17源码解读-render阶段

      本文链接:https://www.haomeiwen.com/subject/ezlncrtx.html