vue3重走来时路之:生命周期钩子知多少?

1,410 阅读5分钟

1. app的mount

这是vue根节点挂载到指定DOM的阶段

单组件的生命周期阶段

其实vue单组件生命周期主要分为4个主要阶段的8个钩子函数:

  • 组件的创建前后:beforeCreatecreated
  • 组件的挂载前后: beforeMountmounted
  • 组件数据更新前后: beforeUpdateupdated
  • 组件的卸载前后: beforeUnmountunmounted

下面我们就针对这几个钩子具体来聊聊

2. beforeCreate

在实例初始化之后、进行数据侦听和事件/侦听器的配置之前同步调用。

在这个阶段,不能访问任何组件的响应式数据或事件(如: computedwatchdata等),也不要去操作响应式数据赋值之类的动作,操作了也会丢失。

3. created

在实例创建完成后被立即同步调用。这时候 数据侦听计算属性方法事件侦听器的回调函数都已配置完毕,但是还没挂载,且 $el property 目前还不可用 在该阶段适合请求一些api初始化数据

在这个阶段,组件的一些响应式数据啊、事件啊之类的都处理好了,就可以去处理一些数据赋值了。 只是说这个时候还没开始挂载数据到模板或者render函数。

4. beforeMount

在挂载开始之前被调用:相关的 render 函数首次被调用。

在这个阶段呢,就是按照我们写的模板或者render转变成虚拟DOM的结构树,,但是这个结构树还没挂载到真实的DOM上面去。这个时候不可以执行DOM操作,比如获取某个DOM节点之类的操作

5. mounted

在实例挂载完成后被调用,这时候 $el 已经被挂载到文档内相应的位置了,但是 mounted 阶段不会保证所有的子组件也都被挂载完成,如果希望等整个视图都渲染完毕执行某些事情的话可以用 nextTick,例:

import { nextTick, onMounted } from 'vue';

onMounted(() => {
  nextTick(() => console.log('在这里可以干自己相干的事情'));
});

在这个阶段的话,其实可以理解为组件的渲染完成了,也已经挂载到对应的DOM节点上了,可以执行一些DOM相关的操作了,如果涉及到子组件的话,还是按照我们上面那样操作比较安全(nextTick)

6. beforeUpdate

在数据发生改变后,DOM 被更新之前被调用。这里适合在现有 DOM 将要被更新之前访问它,比如移除手动添加的事件监听器。

这个就好理解了,数据变更引发的准备开始视图变更。 但是我自己测试了一下,如果修改每个字段,但是该字段没在template使用,也就是说变更的字段不影响视图,是不会触发该钩子的(updated同理)

7. updated

在数据更改导致的虚拟DOM重新渲染和更新完毕之后被调用。但是同样的 updated 阶段不会保证所有的子组件也都被挂载完成,如果希望等整个视图都渲染完毕执行某些事情的话可以用 nextTick,例:

import { nextTick, onUpdated } from 'vue';

onUpdated(() => {
  nextTick(() => console.log('在这里可以干自己相干的事情'));
});

这个阶段也好理解,就是数据更新引发的视图变更完成之后的回调。

但是我自己基本很少用beforeUpdateupdated这两个钩子,主要通过 watchcomputed之后的操作吧。

如果涉及到DOM之类的操作的话,这两钩子就用的比较多吧。

8. beforeUnmount

在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。

这是卸载前执行某些操作,比如说可以解绑一些事件啊,清除一些定时器啊,其他的垃圾回收操作之类的。

或者如果想记录一些数据,又没用keep-alive的话,比如记录搜索条件啥的也可以在这时候操作。

9. unmounted

卸载组件实例后调用。调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。

10. activated

被 keep-alive 缓存的组件激活时调用。

activateddeactivated这两个的话主要场景:用户列表点击进入详情,然后详情返回到列表之类的。

大家如果用到keep-alive的话,还是要小心处理的。比如上面时候应该用缓存,什么时候不用缓存。

11. deactivated

被 keep-alive 缓存的组件失活时调用。

vue3的setup中调用生命周期钩子对应如下:

选项式 APIHook inside setup
beforeCreateNot needed*
createdNot needed*
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked
renderTriggeredonRenderTriggered
activatedonActivated
deactivatedonDeactivated

setup中没有beforeCreatecreated,如果需要在这两个钩子中操作,直接在setup作用域内写你要操作即可。

这里附上官方给的生命周期图供大家参考: image.png

父子组件的生命周期

刚才前面我们说的主要是单页面组件的生命周期,那如果是组件里面嵌套了子组件的时候,他的生命周期又该如何呢?

下面我做了一个测试,例:

1、当我们点击生命周期菜单进入的时候:

image.png 我们可以看到子组件的周期在父组件的mounted之前,子组件如果没用了keep-alive,忽略child activated即可。

2、当我们点击父组件的修改name按钮时:

image.png 我们可以看到子组件的生命周期都在父组件的updated之前

3、当我们点击其他菜单离开的时候:

image.png 我们可以看到子组件的周期也在父组件的unmounted之前都执行完毕了。 而且我们发现子组件的deactivated是在子组件的unmounted之前执行的

由上面两图我们得出结论:

  • 挂载阶段为如下:

父beforeCreate > 父created > 父beforeMount > 子beforeCreate > 子created > 子beforeMount > 子mounted > 子activated > 父mounted

  • 数据更新阶段为如下:

父beforeUpdate > 子beforeUpdate > 子updated > 父updated

  • 卸载阶段为如下:

父beforeUnmount > 子beforeUnmount > 子deactivated > 子unmounted > 父unmounted

其他的一些钩子

12. errorCaptured

在捕获一个来自后代组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

13. renderTracked

跟踪虚拟 DOM 重新渲染时调用。钩子接收 debugger event 作为参数。此事件告诉你哪个操作跟踪了组件以及该操作的目标对象和键。

14. renderTriggered

当虚拟 DOM 重新渲染被触发时调用。和 renderTracked 类似,接收 debugger event 作为参数。此事件告诉你是什么操作触发了重新渲染,以及该操作的目标对象和键。

errorCapturedrenderTrackedrenderTriggered的详细说明可参考:传送门