生命周期:Vue.js 2.x&Vue.js 3.0区别
// 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 请求获取数据。
2:Vue.js 2.x&Vue.js 3.0区别
- 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。
3:onBeforeMount 和 onMounted
- onBeforeMount 注册的 beforeMount 钩子函数会在组件挂载之前执行
- onMounted 注册的 mounted 钩子函数会在组件挂载之后执行
问题解决:在组件初始化阶段,对于发送一些 Ajax 异步请求的逻辑,是应该放在 created 钩子函数中,还是应该放在 mounted 钩子函数中?
其实都可以,因为 created 和 mounted 钩子函数执行的时候都能拿到组件数据,它们执行的顺序虽然有先后,但都会在一个 Tick 内执行完毕,而异步请求是有网络耗时的,其耗时远远大于一个 Tick 的时间。
所以,你无论在 created 还是在 mounted 里发请求,都要等请求的响应回来,然后更新数据,再触发组件的重新渲染。
更推荐在 setup 函数中执行,因为从语义化的角度来看这样更合适。
如果你想依赖 DOM 去做一些初始化操作,那就只能把相关逻辑放在 mounted 钩子函数中了,这样你才能拿到组件渲染后的 DOM。
对于嵌套组件,组件在挂载相关的生命周期钩子函数时,先执行父组件的 beforeMount,然后是子组件的 beforeMount,接着是子组件的 mounted ,最后执行父组件的 mounted。
4:onBeforeUpdate 和 onUpdated
- onBeforeUpdate 注册的 beforeUpdate 钩子函数会在组件更新之前执行
- onUpdated 注册的 updated 钩子函数会在组件更新之后执行
在 beforeUpdate 钩子函数执行时,组件的 DOM 还未更新,如果你想在组件更新前访问 DOM ,比如手动移除已添加的事件监听器,你可以注册这个钩子函数。
在 updated 钩子函数执行时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。如果要监听数据的改变并执行某些逻辑,最好不要使用 updated 钩子函数而用计算属性或 watcher 取而代之,因为任何数据的变化导致的组件更新都会执行 updated 钩子函数。另外注意, 不要在 updated 钩子函数中更改数据,因为这样会再次触发组件更新,导致无限递归更新 。
父组件的更新不一定会导致子组件的更新,因为Vue.js 的更新粒度是组件级别的。
5:onBeforeUnmount 和 onUnmounted
- onBeforeUnmount 注册的 beforeUnMount 钩子函数会在组件销毁之前执行
- onUnmounted 注册的 unmounted 钩子函数会在组件销毁之后执行
组件的销毁过程和渲染过程类似,都是递归的过程。
对于嵌套组件,组件在执行销毁相关的生命周期钩子函数时,先执行父组件的 beforeUnmount,再执行子组件的 beforeUnmount,然后执行子组件的 unmounted ,最后执行父组件的 unmounted。
在组件内部创建一个定时器,就应该在 beforeUnmount 或者 unmounted 钩子函数中清除
<template>
<div>
<div>
<p>{{count}}</p>
</div>
</div>
</template>
<script>
import { ref, onBeforeUnmount } from 'vue'
export default {
setup () {
const count = ref(0)
const timer = setInterval(() => {
console.log(count.value++)
}, 1000)
onBeforeUnmount(() => {
clearInterval(timer)
})
return {
count
}
}
}
</script>
如果你不清除,就会发现组件销毁后,虽然 DOM 被移除了,计时器仍然存在,并且会一直计时并在控制台输出,这就造成了不必要的内存泄漏。
6:onErrorCaptured
errorCaptured 本质上是捕获一个来自子孙组件的错误,它返回 true 就可以阻止错误继续向上传播。
7:onRenderTracked 和 onRenderTriggered
onRenderTracked 和 onRenderTriggered 是 Vue.js 3.0 新增的生命周期 API,它们是在开发阶段渲染调试用的。
- 在执行完依赖收集后,会执行 onTrack 函数,也就是遍历执行我们注册的 renderTracked 钩子函数。
- 在遍历执行 effects 的时候会执行 onTrigger 函数,也就是遍历执行我们注册的 renderTriggered 钩子函数。
<template>
<div>
<div>
<p>{{count}}</p>
<button @click="increase">Increase</button>
</div>
</div>
</template>
<script>
import { ref, onRenderTracked, onRenderTriggered } from 'vue'
export default {
setup () {
const count = ref(0)
function increase () {
count.value++
}
onRenderTracked((e) => {
console.log(e)
debugger
})
onRenderTriggered((e) => {
console.log(e)
debugger
})
return {
count,
increase
}
}
}
</script>