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.', );}