自我介绍:大家好,我是吉帅振的网络日志;微信公众号:吉帅振的网络日志;前端开发工程师,工作4年,去过上海、北京,经历创业公司,进过大厂,现在郑州敲代码。
Vue.js 组件的生命周期包括创建、更新、销毁等过程。在这些过程中也会运行叫生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。在 Vue.js 2.x 中,我们通常会在组件对象中定义一些生命周期钩子函数,到了 Vue.js 3.0,依然兼容 Vue.js 2.x 生命周期的语法,但是 Composition API 提供了一些生命周期函数的 API,让我们可以主动注册不同的生命周期。
// Vue.js 2.x 定义生命周期钩子函数
export default {
created() {
// 做一些初始化工作
},
mounted() {
// 可以拿到 DOM 节点
},
beforeDestroy() {
// 做一些清理操作
}
}
// Vue.js 3.x 生命周期 API 改写上例
import { onMounted, onBeforeUnmount } from 'vue'
export default {
setup() {
// 做一些初始化工作
onMounted(() => {
// 可以拿到 DOM 节点
})
onBeforeUnmount(()=>{
// 做一些清理操作
})
}
}
可以看到,在 Vue.js 3.0 中,setup 函数已经替代了 Vue.js 2.x 的 beforeCreate 和 created 钩子函数,我们可以在 setup 函数做一些初始化工作,比如发送一个异步 Ajax 请求获取数据。我们用 onMounted API 替代了 Vue.js 2.x 的 mounted 钩子函数,用 onBeforeUnmount API 替代了 Vue.js 2.x 的 beforeDestroy 钩子函数。其实,Vue.js 3.0 针对 Vue.js 2.x 的生命周期钩子函数做了全面替换,映射关系如下:
beforeCreate -> 使用 setup()
created -> 使用 use setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy-> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
errorCaptured -> onErrorCaptured
除此之外,Vue.js 3.0 还新增了两个用于调试的生命周期 API:onRenderTracked 和 onRenderTriggered。那么,这些生命周期钩子函数内部是如何实现的?它们又分别在组件生命周期的哪些阶段执行的?分别适用于哪些开发场景?带着这些疑问,我们来深入学习生命周期钩子函数背后的实现原理。
首先,我们来看这些钩子函数是如何注册的,先来看一下它们的实现:
const onBeforeMount = createHook('bm' /* BEFORE_MOUNT */)
const onMounted = createHook('m' /* MOUNTED */)
const onBeforeUpdate = createHook('bu' /* BEFORE_UPDATE */)
const onUpdated = createHook('u' /* UPDATED */)
const onBeforeUnmount = createHook('bum' /* BEFORE_UNMOUNT */)
const onUnmounted = createHook('um' /* UNMOUNTED */)
const onRenderTriggered = createHook('rtg' /* RENDER_TRIGGERED */)
const onRenderTracked = createHook('rtc' /* RENDER_TRACKED */)
const onErrorCaptured = (hook, target = currentInstance) => {
injectHook('ec' /* ERROR_CAPTURED */, hook, target)
}
我们发现除了 onErrorCaptured,其他钩子函数都是通过 createHook 函数创建的,通过传入不同的字符串来表示不同的钩子函数。那么,我们就来分析一下 createHook 钩子函数的实现原理:
const createHook = function(lifecycle) {
return function (hook, target = currentInstance) {
injectHook(lifecycle, hook, target)
}
}
createHook 会返回一个函数,它的内部通过 injectHook 注册钩子函数。你可能会问,这里为什么要用 createHook 做一层封装而不直接使用 injectHook API 呢?比如:
const onBeforeMount = function(hook,target = currentInstance) {
injectHook('bm', hook, target)
}
const onMounted = function(hook,target = currentInstance) {
injectHook('m', hook, target)
}
这样实现当然也是可以的,不过,我