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