1、useEffect 源码分析
mount 阶段
function mountEffectImpl(fiberFlags, hookFlags, create, deps): void {
// 生成 hook 对象
const hook = mountWorkInProgressHook();
// 获取更新的依赖
const nextDeps = deps === undefined ? null : deps;
currentlyRenderingFiber.flags |= fiberFlags;
// 保存最新生成的 effct 对象(多个effect对象、单向环状链表)
hook.memoizedState = pushEffect(
HookHasEffect | hookFlags,
create,
undefined,
nextDeps,
);
}
// 创建 effect 对象的函数
function pushEffect(tag, create, destroy, deps) {
const effect: Effect = {
tag,
create,
destroy,
deps,
next: (null: any),
};
// 保存 update 对象的 componentUpdateQueue 队列
let componentUpdateQueue: null | FunctionComponentUpdateQueue = (currentlyRenderingFiber.updateQueue: any);
if (componentUpdateQueue === null) {
componentUpdateQueue = createFunctionComponentUpdateQueue();
currentlyRenderingFiber.updateQueue = (componentUpdateQueue: any);
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;
}
}
// 返回 effect 对象
return effect;
}
// 创建 hook 对象的函数
function mountWorkInProgressHook(): Hook {
const hook: Hook = {
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
next: null,
};
if (workInProgressHook === null) {
// This is the first hook in the list
currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
} else {
// Append to the end of the list
workInProgressHook = workInProgressHook.next = hook;
}
return workInProgressHook;
}
update 阶段
function updateEffectImpl(fiberFlags, hookFlags, create, deps): void {
// 生成 hook 对象(此函数参考 useState 那一节)
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
let destroy = undefined;
if (currentHook !== null) {
// 取出上次产生的 effect 的 destory 函数
const prevEffect = currentHook.memoizedState;
destroy = prevEffect.destroy;
if (nextDeps !== null) {
const prevDeps = prevEffect.deps;
// 依赖没有变化时
if (areHookInputsEqual(nextDeps, prevDeps)) {
// 保障单项链表位置的一致性
hook.memoizedState = (hookFlags, create, destroy, nextDeps);
// 中断
return;
}
}
}
// 依赖发生变化时执行以下
currentlyRenderingFiber.flags |= fiberFlags;
hook.memoizedState = pushEffect(
HookHasEffect | hookFlags,
create,
destroy,
nextDeps,
);
}
2、useLayoutEffect 源码分析
mount 阶段
function mountLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
// 最终调用 mountEffectImpl
return mountEffectImpl(UpdateEffect, HookLayout, create, deps);
}
update 阶段
function updateLayoutEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
// mountEffectImpl
return updateEffectImpl(UpdateEffect, HookLayout, create, deps);
}
3、执行流程
// 进入 commit 阶段
commitRoot(root)
|
|
V
commitRootImpl(root, renderPriorityLevel) --> commitLayoutEffects(root, lanes);
| |
| |
V V
commitBeforeMutationEffects(); commitLifeCycles()
| |
| |
V V
flushPassiveEffects() commitHookEffectListMount
scheduleCallback( // Mount
NormalSchedulerPriority, const create = effect.create;
() => { effect.destroy = create();
flushPassiveEffects();
return null;
}
);