第六章 构建FiberTree(React18源码解析六)

166 阅读3分钟

第一章 JSX(React18源码解析一)
第二章 实现Virtual DOM(React18源码解析二)
第三章 根节点关联根Fiber(React18源码解析三)
第四章 初始化UpdateQueue、添加update(React18源码解析四)
第五章 实现时间切片函数和拷贝Fiber(React18源码解析五)
第六章 构建FiberTree(React18源码解析六)
第七章 commit(React18源码解析七)
第八章 React中的事件(React18源码解析八)
第九章 useReducer、useState(React18源码解析九)
第十章 React的dom diff(React18源码解析十)
第十一章 React的Effect(React18源码解析十一)
第十二章 React的同步、并发渲染(React18源码解析十二)
第十三章 React高优打断低优、饥饿问题(React18源码解析十三)

构建过程说明

ReactFiberWorkLoop.old.js模块定义一个全局变量workInProgress(当前工作fiber),renderRootConcurrent(并发)调workLoopConcurrent、renderRootSync(同步)调workLoopSync,两workLoop函数都定义一个while(workInProgress !== null)循环调用performUnitOfWork,并传入OldRootFiber、NewRootFiber开始构建fiber tree,performUnitOfWork会走beginWork,并根据NewFiber得到child Virtual DOM,再根据fiber.tag、child Virtual DOM创建出child fiber,并确定它们间的关系FatherFiber.child指向第一个ChildFiber,每个ChidlFiber.return指向FatherFiber,兄弟Fiber是正向单链表,PreFiber.sibling指向NextFiber(在构建时当children为Array,会走一个特定分支来实现此逻辑,用sibling明确兄弟Fiber间的关系也是为后面completeWork服务,返回FirstChildFiber),beginWork会返回ChildFiber并赋给workInProgress,因workLoop循环会继续调用beginWork(及继续向下执行),当beginWork无返回时及CurenntFiber无ChildFiber调用completeUnitOfWork(内部定义一个while (completedWork !== null)循环)并传入CurrentFiber内部调用completeWork,在completeWork中构建真实dom、添加副作用标识、更新fiber.updateQueue等,接着看CurrentFiber.sibling(利用到beginWork阶段构建的关系)是否为空,不为空赋给workInProgress因循环回过头来重新调用beginWork,为空因completeUnitOfWork内循环关系拿CurrentFiber.return(利用到beginWork阶段构建的关系)接着调用completeUnitOfWork,一直循环,在beginWork向下completeWork向上的过程中,当completeUnitOfWork跳出循环、workInProgress为空时workLoop构建完毕,此时FiberTree构建完成

performUnitOfWork函数

//react-18.0.0/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
function performUnitOfWork(unitOfWork) {
  const current = unitOfWork.alternate;

  let next;
  if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {
    next = beginWork(current, unitOfWork, subtreeRenderLanes);
  } else {
    next = beginWork(current, unitOfWork, subtreeRenderLanes);
  }

  unitOfWork.memoizedProps = unitOfWork.pendingProps;
  if (next === null) {
    completeUnitOfWork(unitOfWork);
  } else {
    workInProgress = next;
  }

  ReactCurrentOwner.current = null;
}

beginWork函数

//react-18.0.0/packages/react-reconciler/src/ReactFiberBeginWork.old.js
function beginWork(current,workInProgress,renderLanes){

  switch (workInProgress.tag) {
    case IndeterminateComponent: {
      return mountIndeterminateComponent(
        current,
        workInProgress,
        workInProgress.type,
        renderLanes,
      );
    }
    case LazyComponent: {
      const elementType = workInProgress.elementType;
      return mountLazyComponent(
        current,
        workInProgress,
        elementType,
        renderLanes,
      );
    }
    case FunctionComponent: {
      const Component = workInProgress.type;
      const unresolvedProps = workInProgress.pendingProps;
      const resolvedProps =
        workInProgress.elementType === Component
          ? unresolvedProps
          : resolveDefaultProps(Component, unresolvedProps);
      return updateFunctionComponent(
        current,
        workInProgress,
        Component,
        resolvedProps,
        renderLanes,
      );
    }
    case ClassComponent: {
      const Component = workInProgress.type;
      const unresolvedProps = workInProgress.pendingProps;
      const resolvedProps =
        workInProgress.elementType === Component
          ? unresolvedProps
          : resolveDefaultProps(Component, unresolvedProps);
      return updateClassComponent(
        current,
        workInProgress,
        Component,
        resolvedProps,
        renderLanes,
      );
    }
    case HostRoot:
      return updateHostRoot(current, workInProgress, renderLanes);
    case HostComponent:
      return updateHostComponent(current, workInProgress, renderLanes);
    case HostText:
      return updateHostText(current, workInProgress);
    case SuspenseComponent:
      return updateSuspenseComponent(current, workInProgress, renderLanes);
    case HostPortal:
      return updatePortalComponent(current, workInProgress, renderLanes);
    case ForwardRef: {
      const type = workInProgress.type;
      const unresolvedProps = workInProgress.pendingProps;
      const resolvedProps =
        workInProgress.elementType === type
          ? unresolvedProps
          : resolveDefaultProps(type, unresolvedProps);
      return updateForwardRef(
        current,
        workInProgress,
        type,
        resolvedProps,
        renderLanes,
      );
    }
    case Fragment:
      return updateFragment(current, workInProgress, renderLanes);
    case Mode:
      return updateMode(current, workInProgress, renderLanes);
    case Profiler:
      return updateProfiler(current, workInProgress, renderLanes);
    case ContextProvider:
      return updateContextProvider(current, workInProgress, renderLanes);
    case ContextConsumer:
      return updateContextConsumer(current, workInProgress, renderLanes);
    case MemoComponent: {
      const type = workInProgress.type;
      const unresolvedProps = workInProgress.pendingProps;
      // Resolve outer props first, then resolve inner props.
      let resolvedProps = resolveDefaultProps(type, unresolvedProps);
      if (__DEV__) {
        if (workInProgress.type !== workInProgress.elementType) {
          const outerPropTypes = type.propTypes;
          if (outerPropTypes) {
            checkPropTypes(
              outerPropTypes,
              resolvedProps, // Resolved for outer only
              'prop',
              getComponentNameFromType(type),
            );
          }
        }
      }
      resolvedProps = resolveDefaultProps(type.type, resolvedProps);
      return updateMemoComponent(
        current,
        workInProgress,
        type,
        resolvedProps,
        renderLanes,
      );
    }
    case SimpleMemoComponent: {
      return updateSimpleMemoComponent(
        current,
        workInProgress,
        workInProgress.type,
        workInProgress.pendingProps,
        renderLanes,
      );
    }
    case IncompleteClassComponent: {
      const Component = workInProgress.type;
      const unresolvedProps = workInProgress.pendingProps;
      const resolvedProps =
        workInProgress.elementType === Component
          ? unresolvedProps
          : resolveDefaultProps(Component, unresolvedProps);
      return mountIncompleteClassComponent(
        current,
        workInProgress,
        Component,
        resolvedProps,
        renderLanes,
      );
    }
    case SuspenseListComponent: {
      return updateSuspenseListComponent(current, workInProgress, renderLanes);
    }
    case ScopeComponent: {
      if (enableScopeAPI) {
        return updateScopeComponent(current, workInProgress, renderLanes);
      }
      break;
    }
    case OffscreenComponent: {
      return updateOffscreenComponent(current, workInProgress, renderLanes);
    }
    case LegacyHiddenComponent: {
      if (enableLegacyHidden) {
        return updateLegacyHiddenComponent(
          current,
          workInProgress,
          renderLanes,
        );
      }
      break;
    }
    case CacheComponent: {
      if (enableCache) {
        return updateCacheComponent(current, workInProgress, renderLanes);
      }
      break;
    }
    case TracingMarkerComponent: {
      if (enableTransitionTracing) {
        return updateTracingMarkerComponent(
          current,
          workInProgress,
          renderLanes,
        );
      }
      break;
    }
  }
}

completeUnitOfWork函数

//react-18.0.0/packages/react-reconciler/src/ReactFiberWorkLoop.old.js
function completeUnitOfWork(unitOfWork) {
  let completedWork = unitOfWork;
  do {
    const current = completedWork.alternate;
    const returnFiber = completedWork.return;
    if ((completedWork.flags & Incomplete) === NoFlags) {
      setCurrentDebugFiberInDEV(completedWork);
      let next;
      if (
        !enableProfilerTimer ||
        (completedWork.mode & ProfileMode) === NoMode
      ) {
        next = completeWork(current, completedWork, subtreeRenderLanes);
      } else {
        startProfilerTimer(completedWork);
        next = completeWork(current, completedWork, subtreeRenderLanes);
        stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);
      }
      resetCurrentDebugFiberInDEV();

      if (next !== null) {
        workInProgress = next;
        return;
      }
    } else {
      const next = unwindWork(current, completedWork, subtreeRenderLanes);

      if (next !== null) {
        next.flags &= HostEffectMask;
        workInProgress = next;
        return;
      }

      if (
        enableProfilerTimer &&
        (completedWork.mode & ProfileMode) !== NoMode
      ) {
        stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);
        let actualDuration = completedWork.actualDuration;
        let child = completedWork.child;
        while (child !== null) {
          actualDuration += child.actualDuration;
          child = child.sibling;
        }
        completedWork.actualDuration = actualDuration;
      }

      if (returnFiber !== null) {
        returnFiber.flags |= Incomplete;
        returnFiber.subtreeFlags = NoFlags;
        returnFiber.deletions = null;
      } else {
        workInProgressRootExitStatus = RootDidNotComplete;
        workInProgress = null;
        return;
      }
    }

    const siblingFiber = completedWork.sibling;
    if (siblingFiber !== null) {
      workInProgress = siblingFiber;
      return;
    }
    completedWork = returnFiber;
    workInProgress = completedWork;
  } while (completedWork !== null);
}

completeWork函数

//react-18.0.0/packages/react-reconciler/src/ReactFiberCompleteWork.old.js
略,实在太长了,就不粘了

备注:

本文为清晰展现出本文核心逻辑把粘贴的源码中参数校验、typescript类型、不相关逻辑等已删除