生命周期 注入
function injectHook(type, hook, target = currentInstance, prepend = false) {
if (target) {
if (isRootHook(type) && target.$pageInstance) {
if (target.type.__reserved) {
return;
}
if (target !== target.$pageInstance) {
target = target.$pageInstance;
if (isRootImmediateHook(type)) {
const proxy = target.proxy;
callWithAsyncErrorHandling(
hook.bind(proxy),
target,
type,
ON_LOAD === type ? [proxy.$page.options] : []
);
}
}
}
const hooks = target[type] || (target[type] = []);
const wrappedHook = hook.__weh || (hook.__weh = (...args) => {
if (target.isUnmounted) {
return;
}
pauseTracking();
const reset = setCurrentInstance(target);
const res = callWithAsyncErrorHandling(hook, target, type, args);
reset();
resetTracking();
return res;
});
if (prepend) {
hooks.unshift(wrappedHook);
} else {
hooks.push(wrappedHook);
}
return wrappedHook;
} else if (!!(process.env.NODE_ENV !== "production")) {
const apiName = toHandlerKey(
(ErrorTypeStrings$1[type] || type.replace(/^on/, "")).replace(/ hook$/, "")
);
warn$1(
`${apiName} is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup().` + (` If you are using async setup(), make sure to register lifecycle hooks before the first await statement.` )
);
}
}
const createHook = (lifecycle) => (hook, target = currentInstance) => (
// post-create lifecycle registrations are noops during SSR (except for serverPrefetch)
(!isInSSRComponentSetup || lifecycle === "sp") && injectHook(lifecycle, (...args) => hook(...args), target)
);
const onBeforeMount = createHook("bm");
const onMounted = createHook("m");
const onBeforeUpdate = createHook("bu");
const onUpdated = createHook("u");
const onBeforeUnmount = createHook("bum");
const onUnmounted = createHook("um");
const onServerPrefetch = createHook("sp");
const onRenderTriggered = createHook(
"rtg"
);
const onRenderTracked = createHook(
"rtc"
);
function onErrorCaptured(hook, target = currentInstance) {
injectHook("ec", hook, target);
}
function onBeforeActivate(hook, target) {
registerKeepAliveHook(hook, "ba", target);
}
function onActivated(hook, target) {
registerKeepAliveHook(hook, "a", target);
}
function onBeforeDeactivate(hook, target) {
registerKeepAliveHook(hook, "bda", target);
}
function onDeactivated(hook, target) {
registerKeepAliveHook(hook, "da", target);
}
fn->registerLifecycleHook->createHook->injectHook
- 判断组件活跃
- isRootHook
- hooks初始化
- 包装hook
4.1 isUnmounted跳过
卸载不执行 4.2 setCurrentInstance()
4.3 callWithAsyncErrorHandling
4.4 reset
重置当前组件 4.5 resetTracking
重置追踪 - 根据prepend来控制顺序
生命周期 触发
mountElement
queuePostRenderEffect(() => {
vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode);
needCallTransitionHooks && transition.enter(el);
dirs && invokeDirectiveHook(vnode, null, parentComponent, "mounted");
}, parentSuspense);
patchElement
if (vnodeHook = newProps.onVnodeBeforeUpdate) {
invokeVNodeHook(vnodeHook, parentComponent, n2, n1);
}
if ((vnodeHook = newProps.onVnodeUpdated) || dirs) {
queuePostRenderEffect(() => {
vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, n2, n1);
dirs && invokeDirectiveHook(n2, n1, parentComponent, "updated");
}, parentSuspense);
}
setupRenderEffect
componentUpdateFn
if (!isAsyncWrapperVNode && (vnodeHook = props && props.onVnodeBeforeMount)) {
invokeVNodeHook(vnodeHook, parent, initialVNode);
}
if (!isAsyncWrapperVNode && (vnodeHook = props && props.onVnodeMounted)) {
const scopedInitialVNode = initialVNode;
queuePostRenderEffect(
() => invokeVNodeHook(vnodeHook, parent, scopedInitialVNode),
parentSuspense
);
}
if (vnodeHook = next.props && next.props.onVnodeBeforeUpdate) {
invokeVNodeHook(vnodeHook, parent, next, vnode);
}
if (vnodeHook = next.props && next.props.onVnodeUpdated) {
queuePostRenderEffect(
() => invokeVNodeHook(vnodeHook, parent, next, vnode),
parentSuspense
);
}
unmount
if (shouldInvokeVnodeHook && (vnodeHook = props && props.onVnodeBeforeUnmount)) {
invokeVNodeHook(vnodeHook, parentComponent, vnode);
}
if (shouldInvokeVnodeHook && (vnodeHook = props && props.onVnodeUnmounted) || shouldInvokeDirs) {
queuePostRenderEffect(() => {
vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode);
shouldInvokeDirs && invokeDirectiveHook(vnode, null, parentComponent, "unmounted");
}, parentSuspense);
}
function invokeVNodeHook(hook, instance, vnode, prevVNode = null) {
callWithAsyncErrorHandling(hook, instance, 7, [
vnode,
prevVNode
]);
}
instance->element mount->setupRenderEffect->patch->unmount