Appearance
useLayoutEffect
作用
其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。
尽可能使用标准的 useEffect 以避免阻塞视觉更新。
useLayoutEffect 的保存
js
function mountEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null
): void {
return mountEffectImpl(
UpdateEffect | PassiveEffect,
HookPassive,
create,
deps
);
}
function mountLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null
): void {
return mountEffectImpl(UpdateEffect, HookLayout, create, deps);
}可见其对于 effect 的创建和保存跟 useEffect 是一样的,只是其 FiberNode.flags 和 effect.tag 不同
执行时机
在函数组件 useLayoutEffect 执行是在 Scheduler 任务调度的 commit 阶段的 commitMutationEffects 和 commitLayoutEffects
其中分为 destroy 的执行 和 create 的执行两个过程,下面分别看这两个过程
commitMutationEffects
在这个阶段 执行 useLayoutEffect 的 destroy 回调函数
commitLayoutEffects
在这个阶段 执行 useLayoutEffect 的 create 回调函数
结论
执行时机
useLayoutEffect的destroy函数: 在flushPassiveEffects阶段执行,所以其在 DOM 更新之前useLayoutEffect的create函数: 在flushPassiveEffects阶段执行,所以其在 DOM 更新之前
执行顺序
useLayoutEffect的destroy函数: 在flushPassiveEffects阶段执行,按照先父后子的顺序执行useLayoutEffect的create函数: 在flushPassiveEffects阶段执行,按照先子后父的顺序执行
关键信息
- fiberFlags
- 初始化渲染阶段 : PassiveEffect | PassiveStaticEffect
- 更新 渲染阶段 : PassiveEffect
- hookFlags
- 初始化渲染阶段 : HookPassive
- 更新 渲染阶段 : HookPassive
useLayoutEffect 和 useEffect 的异同点
相同点
- 都是 effect 类型的 hook
- 都会在函数组件执行阶段在 FiberNode.memoizedState 上生成一个 hook 对象
- 都会在函数组件执行阶段在 FiberNode.updateQueue 上添加一个 effect 副作用
- 缓存数据结构、语法(deps、create、destroy)都很像
不同点
- 执行时机不同
useLayoutEffect
create 在 commit 的最后阶段(commitLayoutEffects)中才会执行,并生成 destroy
destroy 在 commit 的第二阶段(commitMutationEffects)中如果是函数类型组件的卸载操作,就会执行 destroy 回调
useEffect 是在
flushPassiveEffects 的时候统一执行(destroy -> create)
执行的方式不同
- useLayoutEffect 他是在组件 Commit 阶段同步执行的
- useLayout : 在组件 Commit 阶段收集,然后通过 scheduler 高优先级任务队列回调执行的
