乐趣区

关于前端: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.',
  );
}
退出移动版