React源码解析 之 Fiber的渲染(3)终

786 阅读4分钟

React源码系列

completeWork

相比较beginWork阶段来说,completeWork阶段,处理就比较简单了。同样的,对于completeWork,也是通过workInProgress.tag来判断,走哪些类型逻辑。

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:
      bubbleProperties(workInProgress);
      return null;
    case ClassComponent: {
      const Component = workInProgress.type;
      if (isLegacyContextProvider(Component)) {
        popLegacyContext(workInProgress);
      }
      bubbleProperties(workInProgress);
      return null;
    }

对于completeWork阶段来说,很多类型是不需要处理的,对context栈进行置空处理,和处理一些lane。 因此,这里主要说下HostTextHostComponent类型。

HostText

case HostText: {
      const newText = newProps;
      // 判断是否是update状态。
      if (current && workInProgress.stateNode != null) {
        const oldText = current.memoizedProps;
        //传入Text类型到workInProgress.stateNode上
        updateHostText(current, workInProgress, oldText, newText);
      } else {
        if (typeof newText !== 'string') {
          //...
        }
        
        const rootContainerInstance = getRootHostContainer();
        const currentHostContext = getHostContext();
        //...
        if (wasHydrated) {
          //...
        } else {
          // 通过createTextNode的TextNode
          workInProgress.stateNode = createTextInstance(
            newText,
            rootContainerInstance,
            currentHostContext,
            workInProgress,
          );
        }
      }
      return null;
    }

对于HostText类型,通过current && workInProgress.stateNode != null条件,来区分当前节点,处于什么阶段。

如果处于update阶段的话,即条件为true:此时通过markUpdate(workInProgress),打上标记,当处于commit阶段再执行。

如果处于mounted阶段的话,即条件为false:通过createTextNode的创建TextNode,返回给workInProgress.stateNode

HostComponent

HostComponent为原生DOM组件,通过current !== null && workInProgress.stateNode != null区分mounted:falseupdate:true阶段。

update:

调用updateHostComponent函数,如果current.ref !== workInProgress.ref为true,标记markRef(workInProgress)

对于updateHostComponent函数,复用workInProgress.stateNode为instance。

instance: Instance = workInProgress.stateNode;

调用prepareUpdate函数,返回updateQueue

export function prepareUpdate(
  domElement: Instance,
  type: string,
  oldProps: Props,
  newProps: Props,
  rootContainerInstance: Container,
  hostContext: HostContext,
): null | Array<mixed> {
  // 对属性进行取差
  return diffProperties(
    domElement,
    type,
    oldProps,
    newProps,
    rootContainerInstance,
  );
}

commitRoot阶段

在这里简单说下commitRoot阶段。

对于一个commitRoot阶段,包含三个阶段:before mutationmutationlayout阶段。

before mutation:

初始化清空下,清空副作用,调用commitRootImpl。然后再重置下状态

  // ...
  // 清除回调
  root.callbackNode = null;
  root.callbackPriority = NoLanePriority;

  //合并lane
  let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
  // 重置优先级
  markRootFinished(root, remainingLanes);
    //重置全局变量
  if (root === workInProgressRoot) {
    //处于
    workInProgressRoot = null;
    workInProgress = null;
    workInProgressRootRenderLanes = NoLanes;
  }
 //...
// 调度useEffect
if ((effectTag & Passive) !== NoEffect) {
  if (!rootDoesHavePassiveEffects) {
    rootDoesHavePassiveEffects = true;
    scheduleCallback(NormalSchedulerPriority, () => {
      flushPassiveEffects();
      return null;
    });
  }
}
nextEffect = nextEffect.nextEffect;

调用commitBeforeMutationEffects函数,判断是否是classComponent执行生命周期getSnapshotBeforeUpdate

该函数的返回给componentDidUpdate image.png

image.png

commitBeforeMutationEffects
// 
export function commitBeforeMutationEffects(
  root: FiberRoot,
  firstChild: Fiber,
) {
    //...
  nextEffect = firstChild;
  commitBeforeMutationEffects_begin();
 //...
  return shouldFire;
}
// 
function commitBeforeMutationEffects_begin() {
  while (nextEffect !== null) {
    const fiber = nextEffect;
    //...
    const child = fiber.child;
    if (
      (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags &&
      child !== null
    ) {
      //...
      nextEffect = child;
    } else {
    // Before Mutation 处理完成
      commitBeforeMutationEffects_complete();
    }
  }
}

function commitBeforeMutationEffects_complete() {
  while (nextEffect !== null) {
    const fiber = nextEffect;
    if (__DEV__) {
      //...
    } else {
      try {
      //处理副作用
        commitBeforeMutationEffectsOnFiber(fiber);
      } catch (error) {
        //...
      }
    }
    // 处理兄弟节点
    const sibling = fiber.sibling;
    if (sibling !== null) {
      nextEffect = sibling;
      return;
    }

    nextEffect = fiber.return;
  }
}

function commitBeforeMutationEffectsOnFiber(finishedWork: Fiber) {
  const current = finishedWork.alternate;
  const flags = finishedWork.flags;
  // ...

  if ((flags & Snapshot) !== NoFlags) {
    setCurrentDebugFiberInDEV(finishedWork);

    switch (finishedWork.tag) {
      case FunctionComponent:
      case ForwardRef:
      case SimpleMemoComponent: {
        break;
      }
      case ClassComponent: {
        if (current !== null) {
          const prevProps = current.memoizedProps;
          const prevState = current.memoizedState;
          const instance = finishedWork.stateNode;
          // 调用生命周期
          const snapshot = instance.getSnapshotBeforeUpdate(
            finishedWork.elementType === finishedWork.type
              ? prevProps
              : resolveDefaultProps(finishedWork.type, prevProps),
            prevState,
          );
          //将处理的返回值缓存起来
          instance.__reactInternalSnapshotBeforeUpdate = snapshot;
        }
        break;
      }

mutation

进入mutation阶段,调用commitMutationEffects(root, finishedWork);函数

commitMutationEffects

export function commitMutationEffects(root: FiberRoot, firstChild: Fiber) {
  nextEffect = firstChild;
  commitMutationEffects_begin(root);
}

//...调用commitMutationEffectsOnFiber处理函数类型
commitMutationEffectsOnFiber(fiber, root);
//...

function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) {
  const flags = finishedWork.flags;

  // 根据primaryFlag判断当前组件处于什么组件状态
  const primaryFlags = flags & (Placement | Update | Hydrating);
  outer: switch (primaryFlags) {
    //...处理commitWork
    case Update: {
      const current = finishedWork.alternate;
      commitWork(current, finishedWork);
      break;
    }
  }
}

Layout阶段

到达此阶段后,说明DOM已经渲染完成,(说明mutation阶段完成)。 在该阶段,调用的生命周期和hook已经可以访问到DOM元素了。

commitLayoutEffects(finishedWork, root, lanes);
                    |
commitLayoutEffects_begin(finishedWork, root, committedLanes);
                    |
commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);
                    |
commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
function commitLayoutEffectOnFiber(
  finishedRoot: FiberRoot,
  current: Fiber | null,
  finishedWork: Fiber,
  committedLanes: Lanes,
): void {
  if ((finishedWork.flags & (Update | Callback)) !== NoFlags) {
    switch (finishedWork.tag) {
      // 以下都是FunctionComponent及相关类型
        case FunctionComponent:
        case ForwardRef:
        case SimpleMemoComponent:
        case Block: {
          // 执行useLayoutEffect的回调函数
          commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
          // 调度useEffect的销毁函数与回调函数
          schedulePassiveEffects(finishedWork);
          return;
        }
      case ClassComponent: {
        const instance = finishedWork.stateNode;

        if (finishedWork.flags & Update) {
            //...
            //组件加载完成调用生命周期
              instance.componentDidMount();
          } else {
            const prevProps =
              finishedWork.elementType === finishedWork.type
                ? current.memoizedProps
                : resolveDefaultProps(finishedWork.type, current.memoizedProps);
            const prevState = current.memoizedState;
             //...
             //调用componentDidUpdate生命周期传入getSnapshotBeforeUpdate的返回值
              instance.componentDidUpdate(
                prevProps,
                prevState,
                instance.__reactInternalSnapshotBeforeUpdate,
              );
            
          }
        }
        // 更新队列
          commitUpdateQueue(finishedWork, updateQueue, instance);
        }
        break;
      }
 //...

对于FunctionComponent组件,调用commitHookEffectListMount函数执行副作用。

// 执行副作用useEffect
function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
  const updateQueue: FunctionComponentUpdateQueue | null = (finishedWork.updateQueue: any);
  const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
  if (lastEffect !== null) {
    const firstEffect = lastEffect.next;
    let effect = firstEffect;
    do {
      if ((effect.tag & tag) === tag) {
        // Mount 
        const create = effect.create;
        effect.destroy = create();
      effect = effect.next;
    } while (effect !== firstEffect);
  }
}

对于classComponent组件,根据finishedWork.flags & Update进行判断,mount阶段,调用componentDidMount函数,在update阶段调用instance.componentDidUpdate函数。

最后调用commitUpdateQueue函数,处理effect函数,调用后调。

export function commitUpdateQueue<State>(
  finishedWork: Fiber,
  finishedQueue: UpdateQueue<State>,
  instance: any,
): void {
  // Commit the effects
  const effects = finishedQueue.effects;
  finishedQueue.effects = null;
  if (effects !== null) {
    effects.forEach(effect => {
      const callback = effect.callback;
      if (callback !== null) {
        effect.callback = null;
        callCallback(callback, instance);
      }
    })
  

commitUpdateQueue主要解决setState的回调。

image.png

image.png

结束

这几篇文章主要介绍了React.render的基本流程。