关于前端:React源码Part7CommitMutation阶段

Mutation阶段次要做了什么

1.入口函数:commitMutationEffects()
2.筹备开始执行:commitMutationEffects_begin
3.遍历Effect链表:commitMutationEffects_complete
4.对失去的单Fibre节点进行解决:commitMutationEffectsOnFiber

commitMutationEffects

  • Mutation阶段的入口函数
export function commitMutationEffects(
  root: FiberRoot,
  firstChild: Fiber,
  committedLanes: Lanes,
) {
  inProgressLanes = committedLanes;
  inProgressRoot = root;
  nextEffect = firstChild;

  commitMutationEffects_begin(root);

  inProgressLanes = null;
  inProgressRoot = null;
}

commitMutationEffects_begin

  • 对Effect链表遍历,且如果Fibre节点上有须要删除的child就删commitDeletion(root, childToDelete, fiber)
  • 传入单个Fiber节点给commitMutationEffects_complete解决
function commitMutationEffects_begin(root: FiberRoot) {
  while (nextEffect !== null) {
    const fiber = nextEffect;

    // TODO: Should wrap this in flags check, too, as optimization
    const deletions = fiber.deletions;
    if (deletions !== null) {
      for (let i = 0; i < deletions.length; i++) {
        const childToDelete = deletions[i];
        if (__DEV__) {
          // DEV 环境的货色能够临时不论

        } else {
          try {
            commitDeletion(root, childToDelete, fiber);
          } catch (error) {
            captureCommitPhaseError(childToDelete, fiber, error);
          }
        }
      }
    }

    const child = fiber.child;
    if ((fiber.subtreeFlags & MutationMask) !== NoFlags && child !== null) {
      ensureCorrectReturnPointer(child, fiber);
      nextEffect = child;
    } else {
      commitMutationEffects_complete(root);
    }
  }
}

commitMutationEffects_complete

  • 解决传进来的Fibre节点,其nextEffect有值示意须要对该Fiber进行操作,传入commitMutationEffectsOnFiber解决
  • 如果nextEffect没有值,对其Fibre节点进行遍历和调度,ensureCorrectReturnPointer
function commitMutationEffects_complete(root: FiberRoot) {
  while (nextEffect !== null) {
    const fiber = nextEffect;
    if (__DEV__) {
      // DEV 环境的货色能够临时不论

    } else {
      try {
        commitMutationEffectsOnFiber(fiber, root);
      } catch (error) {
        captureCommitPhaseError(fiber, fiber.return, error);
      }
    }

    const sibling = fiber.sibling;
    if (sibling !== null) {
      ensureCorrectReturnPointer(sibling, fiber.return);
      nextEffect = sibling;
      return;
    }

    nextEffect = fiber.return;
  }
}

commitMutationEffectsOnFiber

  • 对须要操作的Fibre节点进行操作,有ref相干操作的就执行ref相干操作,再依据不同的flags值做不同的DOM操作
  • commitPlacement: 示意解决DOM的插入
  • commitWork:示意对DOM的属性更新
function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) {
  const flags = finishedWork.flags;

  // 是否须要重置文本内容
  if (flags & ContentReset) {
    commitResetTextContent(finishedWork);
  }

 // 解决 ref 相干的操作
  if (flags & Ref) {
    const current = finishedWork.alternate;
    if (current !== null) {
      commitDetachRef(current);
    }
    if (enableScopeAPI) {
      // TODO: This is a temporary solution that allowed us to transition away
      // from React Flare on www.
      if (finishedWork.tag === ScopeComponent) {
        commitAttachRef(finishedWork);
      }
    }
  }
  
  // 依据不同的 flags值执行不同的操作
  const primaryFlags = flags & (Placement | Update | Hydrating);
  outer: switch (primaryFlags) {
    case Placement: { // 插入新的DOM
     
      commitPlacement(finishedWork);
      finishedWork.flags &= ~Placement;
      break;
    }
    case PlacementAndUpdate: { // 更新DOM属性和插入DOM
      // Placement
      commitPlacement(finishedWork);
      finishedWork.flags &= ~Placement;

      // Update
      const current = finishedWork.alternate;
      commitWork(current, finishedWork);
      break;
    }
    case Hydrating: { // SSR 环境下的插入DOM
      finishedWork.flags &= ~Hydrating;
      break;
    }
    case HydratingAndUpdate: { // SSR 环境下的插入DOM和更新DOM
      finishedWork.flags &= ~Hydrating;

      // Update
      const current = finishedWork.alternate;
      commitWork(current, finishedWork);
      break;
    }
    case Update: { // 更新DOM属性
      const current = finishedWork.alternate;
      commitWork(current, finishedWork);
      break;
    }
  }
}

commitContainer

  • commitMutationEffects_complete函数的Switch语句的commitWork或commitPlacement办法都会执行到commitContainer
function commitContainer(finishedWork: Fiber) {
  if (!supportsPersistence) {
    return;
  }

  switch (finishedWork.tag) {
    case ClassComponent:
    case HostComponent:
    case HostText: {
      return;
    }
    case HostRoot:
    case HostPortal: {
      const portalOrRoot: {
        containerInfo: Container,
        pendingChildren: ChildSet,
        ...
      } = finishedWork.stateNode;
      const {containerInfo, pendingChildren} = portalOrRoot;
      replaceContainerChildren(containerInfo, pendingChildren);
      return;
    }
  }
  invariant(
    false,
    'This unit of work tag should not have side-effects. This error is ' +
      'likely caused by a bug in React. Please file an issue.',
  );
}

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理