书接上文数组
effect
也就是在React中咱们常说的side effect,在React中相似像componentDidMount这样的生命周期方法中,由于可能会执行setState这样的方法而产生新的更新,咱们称为side effect即替代。自己FunctionalComponent由于是pure function,因此不会产生任何的异常,而useEffect和useLayoutEffect则是带给产生FunctionalComponent交替能力的挂钩,他们的行为很是相似componentDidMount和componentDidUpdatebash
function createFunctionComponentUpdateQueue(): FunctionComponentUpdateQueue {
return {
lastEffect: null,
};
}
function pushEffect(tag, create, destroy, inputs) {
const effect: Effect = {
tag,
create,
destroy,
inputs,
// Circular
next: (null: any),
};
if (componentUpdateQueue === null) {
componentUpdateQueue = createFunctionComponentUpdateQueue();
componentUpdateQueue.lastEffect = effect.next = effect;
} else {
const lastEffect = componentUpdateQueue.lastEffect;
if (lastEffect === null) {
componentUpdateQueue.lastEffect = effect.next = effect;
} else {
const firstEffect = lastEffect.next;
lastEffect.next = effect;
effect.next = firstEffect;
componentUpdateQueue.lastEffect = effect;
}
}
return effect;
}
复制代码
useLayoutEffect
UpdateEffect
useEffect
UpdateEffect | PassiveEffect
useLayoutEffect
UnmountMutation | MountLayout
useEffect
UnmountPassive | MountPassive
areHookInputsEqual
NoHookEffect
在如下三个阶段都会调用commitHookEffectList
方法,咱们来看一下:异步
commitWork
中commitHookEffectList(UnmountMutation, MountMutation, finishedWork);
commitBeforeMutationLifeCycles
中commitHookEffectList(UnmountSnapshot, NoHookEffect, finishedWork);
commitLifeCycles
中commitHookEffectList(UnmountLayout, MountLayout, finishedWork);
commitHookEffectList
这个方法的内容就是根据传入的unmountTag
和mountTag
来判断是否须要执行对应的destory
和create
方法,这是在每一个Hook
对象的effect
链上的。因此看这部分代码最重要的其实就是看他传入的effectTag
和Hook对象上的effectTag
的对比。ide
对比结果就是:ui
useLayoutEffect
的destory
会在commitWork
的时候被执行;而他的create
会在commitLifeCycles
的时候被执行。useEffect
在这个流程中都不会被执行。能够看出来useLayoutEffect
的执行过程跟componentDidMount
和componentDidUpdate
很是类似,因此React官方也说了,若是你必定要选择一个相似于生命周期方法的Hook,那么useLayoutEffect
是不会错的那个,可是咱们推荐你使用useEffect
,在你清除他们的区别的前提下,后者是更好的选择。spa
那么useEffect
何时被调用呢?code
答案在commitRoot
的最后,他等其余sideEffect
所有commit
完了以后,会执行如下代码:component
if (
enableHooks &&
firstEffect !== null &&
rootWithPendingPassiveEffects !== null
) {
let callback = commitPassiveEffects.bind(null, root, firstEffect);
passiveEffectCallbackHandle = Schedule_scheduleCallback(callback);
passiveEffectCallback = callback;
}复制代码
rootWithPendingPassiveEffects
是在commitAllLifeCycles
的时候若是发现更新中有passive effect
的节点的话,就等于FiberRoot
。orm
if (enableHooks && effectTag & Passive) {
rootWithPendingPassiveEffects = finishedRoot;
}复制代码
这里若是有,则会发起一次Schedule_scheduleCallback
,这个就是咱们以前讲的异步调度模块Scheduler
的方法,流程跟PerformWork
相似,这里咱们再也不重复讲解。对象
但咱们看到这里就清楚了,useEffect
的destory
和create
都是异步调用的,因此他们不会影响本次更新的提交,因此不会由于在effect
中产生了新的更新而致使阻塞DOM渲染的状况。
那么commitPassiveEffects
作了啥呢?
export function commitPassiveHookEffects(finishedWork: Fiber): void {
commitHookEffectList(UnmountPassive, NoHookEffect, finishedWork);
commitHookEffectList(NoHookEffect, MountPassive, finishedWork);
}复制代码
正好对应了useEffect
设置的sideEffect
。