Appearance
参照上一节流程,同样分成创建(mount)和更新(update)过程
useEffect
mount
js
function mountEffect(create, deps) {
return mountEffectImpl(
UpdateEffect | PassiveEffect,
HookPassive,
create,
deps,
);
}
function mountEffectImpl(fiberFlags, hookFlags, create, deps) {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps; // 依赖项
currentlyRenderingFiber.flags |= fiberFlags; // 设置flags
// 保存的是最后一个 effect
hook.memoizedState = pushEffect(
HookHasEffect | hookFlags,
create,
undefined,
nextDeps,
);
}
function pushEffect(tag, create, destroy, deps) {
// 创建effect对象
const effect: Effect = {
tag,
create,
destroy,
deps,
next: (null: any),
};
let componentUpdateQueue = (currentlyRenderingFiber.updateQueue);
// 建立 环状链表
if (componentUpdateQueue === null) {
// 创建 updateQueue保存effect
componentUpdateQueue = createFunctionComponentUpdateQueue();
currentlyRenderingFiber.updateQueue = componentUpdateQueue;
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;
}
update
js
function updateEffectImpl(fiberFlags, hookFlags, create, deps) {
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
let destroy = undefined;
if (currentHook !== null) {
// 保存的最后一个effect
const prevEffect = currentHook.memoizedState;
// effect的销毁函数
// 需要等到 currentHook 的 create 函数执行返回才有 destroy
destroy = prevEffect.destroy;
if (nextDeps !== null) {
// 有依赖项
const prevDeps = prevEffect.deps;
if (areHookInputsEqual(nextDeps, prevDeps)) {
// 依赖项的值没有改变
// 没有变化也要push,保证 wip.memoizedState保存的单向链表顺序正确
pushEffect(hookFlags, create, destroy, nextDeps);
return;
}
}
}
// 依赖项 有改变
currentlyRenderingFiber.flags |= fiberFlags;
// 记录新的 effect
hook.memoizedState = pushEffect(
HookHasEffect | hookFlags,
// 只有包含 HookHasEffect 的flag,才会在本次commit 阶段执行
create,
destroy,
nextDeps,
);
}
useLayoutEffect
js
function mountLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
return mountEffectImpl(UpdateEffect, HookLayout, create, deps);
}
function updateLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
return updateEffectImpl(UpdateEffect, HookLayout, create, deps);
}
相比 useEffect 只是传入的 flag 不同,导致 effect 内部的调用函数不同
流程总结
commitRoot -> beforeCommitMutation 包含 schedule(调度异步更新) -> mutation(实行更新) 包含 layoutEffect 的 destroy函数(mount时为空) -> layout 触发 layoutEffect 的create 同时赋值 destroy -> 回调useEffect 的 destroy 和 create