「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。
Options API 与 setup 中使用生命周期的区别
Vue3目前兼容Vue2的生命周期函数
映射关系
| Options API | setup 中使用 |
|---|---|
| beforeCreate | 不需要 |
| created | 不需要 |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeUnmount | onBeforeUnmount |
| unmounted | onUnmounted |
| errorCaptured | onErrorCaptured |
| renderTracked | onRenderTracked |
| renderTriggered | onRenderTriggered |
| activated | onActivated |
| deactivated | onDeactivated |
- 关于
setup中为什么没有beforeCreate和created,官方文档中有个 tip
因为
setup是围绕beforeCreate和created生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在setup函数中编写。
- 前文 Vue3.0源码学习——Composition API 学习了,在
setup定义的时候组件的实例instance已经创建,因此在setup中使用beforeCreate和created钩子没有意义,也印证了官方文档
setup 中使用生命周期钩子
import { onMounted, onUpdated, onUnmounted } from 'vue'
const MyComponent = {
setup() {
onMounted(() => {
console.log('mounted!')
})
onUpdated(() => {
console.log('updated!')
})
onUnmounted(() => {
console.log('unmounted!')
})
}
}
- 在
setup中使用生命周期钩子的优势在于,不用像Vue2那样将所有同一个生命周期相关的内容都写在这个生命周期函数中,在setup中可以在多处使用同一个生命周期钩子函数,这也体现出了Composition API的优势
源码解析
这里只看setup中生命周期钩子函数
- 如何定位源码:在源码中
ctrl + t随意搜一个生命周期钩子函数比如onMounted,找到源码位置packages\runtime-core\src\apiLifecycle.ts,可以看到所有的生命周期钩子函数都是执行了同一个函数createHook
export const onBeforeMount = createHook(LifecycleHooks.BEFORE_MOUNT)
export const onMounted = createHook(LifecycleHooks.MOUNTED)
export const onBeforeUpdate = createHook(LifecycleHooks.BEFORE_UPDATE)
export const onUpdated = createHook(LifecycleHooks.UPDATED)
export const onBeforeUnmount = createHook(LifecycleHooks.BEFORE_UNMOUNT)
export const onUnmounted = createHook(LifecycleHooks.UNMOUNTED)
export const onServerPrefetch = createHook(LifecycleHooks.SERVER_PREFETCH)
生命周期枚举值
createHook函数入参传入不同的的生命周期名称,并返回另一个函数,这个函数的第一个参数hook要求类型是一个函数,就是用户定义在当前生命周期要执行的代码,最终会执行注入钩子函数injectHook
export const createHook =
<T extends Function = () => any>(lifecycle: LifecycleHooks) =>
(hook: T, target: ComponentInternalInstance | null = currentInstance) =>
// post-create lifecycle registrations are noops during SSR (except for serverPrefetch)
(!isInSSRComponentSetup || lifecycle === LifecycleHooks.SERVER_PREFETCH) &&
injectHook(lifecycle, hook, target)
injectHook接受的第三个参数target就是当前组件的实例,最终会在用户传入的hook上包裹一层,在执行到生命周期的时候进行调用
export function injectHook(
type: LifecycleHooks,
hook: Function & { __weh?: Function },
target: ComponentInternalInstance | null = currentInstance,
prepend: boolean = false
): Function | undefined {
if (target) {
// 拿出实例上的hooks
const hooks = target[type] || (target[type] = [])
// cache the error handling wrapper for injected hooks so the same hook
// can be properly deduped by the scheduler. "__weh" stands for "with error
// handling".
// 对用户传入的hook进行包裹
const wrappedHook =
hook.__weh ||
(hook.__weh = (...args: unknown[]) => {
if (target.isUnmounted) {
return
}
// disable tracking inside all lifecycle hooks
// since they can potentially be called inside effects.
pauseTracking()
// Set currentInstance during hook invocation.
// This assumes the hook does not synchronously trigger other hooks, which
// can only be false when the user does something really funky.
setCurrentInstance(target)
// 执行时是否会出错
const res = callWithAsyncErrorHandling(hook, target, type, args)
unsetCurrentInstance()
resetTracking()
return res
})
if (prepend) {
hooks.unshift(wrappedHook)
} else {
// 将hook存在当前组件实例上,将来执行到钩子函数式,循环调用即可
hooks.push(wrappedHook)
}
return wrappedHook
} else if (__DEV__) {
...
}
}