3.1 KiB
commitMutationEffects 对应 commit 中的 mutation 阶段,这个方法内部是一个 while 循环,遍历 effectList 链表,遍历到的每一个 Fiber 节点首先会判断是否存在 ConentReset 标记,这个标记表示 Fiber 是否需要重置文本节点
commitResetTextContent
然后会判断是否存在 Ref 标记
commitDetachRef
然后进入 mutation 阶段最重要的逻辑:判断 Fiber 阶段是否存在以下 effectTag
- Placement 插入DOM
- Update 更新属性
- Deletion 删除 DOM 节点
- Hydrating SSR 相关
然后根据 effectTag 不同进入不同的处理逻辑
Placement
commitPlacement 如果当前环境不支持 mutation 会直接返回,ReactDOM 下是支持的 首先会根据当前的 Fiber 节点,找到其最近的 Host 类型的父 Fiber 节点,Host 类型包括 HostComponent、HostRoot、HostPortal 和 FundamentalComponent,这几种类型有一个共同点:它们都有对应的 DOM 节点 找到之后先进行各自的前置处理逻辑
getHostParetFiber
一直递归向上查找,直到找到 HostComponent 为止
如果父 Fiber 节点上存在 ConentReset 标记,就要先执行 resetTextConent 函数,然后会找到当前 Fiber 节点的 Host 类型的兄弟节点
getHostSibling
该方法内部有着一个嵌套循环,因为兄弟 HostComponents 的查找可能是跨层级的
为什么要找到最近的兄弟节点 HostComponent?
- 因为 DOM 的插入有两种方法,第一种是 insertBefore 方法,第二种是 appendChild
- 使用 insertBefore 时需要找到兄弟节点
- 使用 appendChild 时需要找到父节点
insertInContainerBefor
内部实际上还是使用了 insertBefore 方法
appendChildToContainer
内部实际上还是使用了 appendChild 方法
PlacementAndUpdate
先调用 commitPlacement 方法,接着调用 commitWork
commitWork
与 Function 有关的类型,会调用 commitHookEffectListUnmount
commitHookEffectListUnmount
会调用 useLayoutEffect 的销毁函数,内部会遍历 EffectList,如果包含传入的 tag,当前是 HookLayout,也就是内部存在 useLayoutEffect 的函数组件,那么会执行它们 useLayoutEffect 的回调函数,也就是 useLayoutEffect 的 return
在执行任意 useEffectLayout 的回调函数之前,会先执行所有 useEffectLayout 的销毁函数
HostComponent 组件,会调用 commitUpdate 方法
commitUpdate
且接收的 updatePayload 参数就是当前 Fiber 组件的 updateQueue 属性 内部最终会调用 updateProperties 函数来更新 DOM 的 props
Deletion
会执行 commitDeletion 函数
commitDeletion
如果支持 mutation,那么会调用 unmountHostComponents
unmountHostComponents
commitNestedUnmount
递归删除 Fiber 子节点
commitUnmount
对于 FunctionComponent 类型的组件,需要执行 enqueuePendingPassiveHookEffectUnmount 函数,也就是注册需要被执行的 useEffect 回调函数
对于 ClassComponents 类型的组件,会执行它的 componentWillUnmount 生命周期函数
对于 HostComponents 类型的组件,会解绑它的 ref 属性