Vue生命周期

315 阅读5分钟

先放两张Vue3的生命周期图供参考

Vue3生命周期图

英文版

lifecycle.png

中文版

lifecycle-chinese.png

生命周期介绍

每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行被称为生命周期钩子的函数,让开发者有机会在特定阶段运行自己的代码。

Vue2到Vue3的破坏性改动

  • destroyed 生命周期选项被重命名为 unmounted
  • beforeDestroy 生命周期选项被重命名为 beforeUnmount

选项式和组合式的区别

在选项式中,被称为生命周期选项

在组合式中,被称为生命周期钩子

注:下文中生命周期钩子和生命周期选项统称为钩子或者生命周期钩子。

选项式除了多两个生命周期钩子 created 和 beforeCreate,其他生命周期钩子和组合式没有什么区别,只是组合式的生命周期钩子多了前缀 on 在组合式中使用 setup 钩子来替代 created 和 beforeCreate 钩子,所以不需要这两个生命周期钩子。

注:如果在选项式中使用组合式的 setup() 钩子,那么setup() 钩子会在所有选项式 API 钩子之前调用,beforeCreate() 也不例外。

存在keep-alive时的生命周期

以下生命周期钩子是存在keep-alive时特有的:

  • activated
  • deactivated 当一个组件实例从 DOM 上移除但因为被 <KeepAlive> 缓存而仍作为组件树的一部分时,它将变为不活跃状态而不是被卸载。当一个组件实例作为缓存树的一部分插入到 DOM 中时,它将重新被激活

需要注意的是:

  • activated 在组件挂载时也会调用,并且先调用 mounted 再调用 activated
  • deactivated 在组件卸载时也会调用,并且先调用 beforeUnmount,再调用 deactivated,然后调用 unmounted
  • 这两个钩子不仅适用于 <KeepAlive> 缓存的根组件,也适用于缓存树中的后代组件。

服务端渲染时的生命周期

服务端渲染,指在服务器端渲染 Vue 组件,生成 html 字符串,返回给浏览器端。 与传统的服务端渲染不同,这里说的服务端渲染,最后还会在浏览器端将静态的 HTML“激活”(hydrate) 为能够交互的客户端应用。

由于服务端渲染的特殊性,以下生命周期钩子不会触发:

  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • beforeUnmount
  • unmounted
  • renderTracked
  • renderTriggered
  • activated
  • deactivated 其实也很好理解,因为服务端渲染是个一次性渲染静态 html 的过程,所以没有也不需要上述生命周期钩子。 上述生命周期钩子在服务端渲染过程中不会触发,但是在浏览器端“激活”(hydrate)之后,是能正常触发的。 同时,服务端渲染还多了一个特殊的钩子:
  • serverPrefetch 这个钩子仅会在服务端渲染中执行,可以用于执行一些仅在服务端才有的数据抓取过程。

源码解析

前面介绍了很多生命周期相关的内容,接下来,我们通过源码来印证前面介绍的内容。

对选项式生命周期的处理

beforeCreate option.png create.png created option.png 从上图的源码可以看出,在初始化选项之前,先调用了 beforeCreate 钩子,再依次对 props、inject、methods、data、computed、watch 这些选项进行初始化,然后调用 created 钩子。 applyOptions.png 从上图的源码中可以看到,对于选项式的生命周期选项会注册为生命周期钩子。

迁移构建对破坏性改动的处理

compat.png 前面我们介绍了 Vue2 到 Vue3 对 beforeDestroy 和 destroyed 做了破坏性改动,改名为了 beforeUnmount 和 unmount,从上图我们可以看到,@vue/compat 迁移构建对这一破坏性改动做了兼容性处理。

setup钩子会在所有选项式 API 钩子之前调用

对于这一点的源码印证,涉及的调用链路比较长,这里给出简略版。 call setup().png handleSetupResult.png finishComponentSetup.png

从上图的源码我们可以看到,经过漫长的调用链路(setup -> handleSetupResult -> finishComponentSetup -> applyOptions),我们终于来到了上文介绍的对选项式进行处理的源码。 由此,也可以看出,setup 钩子确实会在所有选项式 API 钩子之前调用。

对 KeepAlive 缓存组件生命周期的处理

挂载组件

长图预警

mount.png

由于这一部分只为了印证对 KeepAlive 缓存组件生命周期的处理,我们跳过前面 patch 的逻辑,直接看这个 componentUpdateFn 函数,这里需要说明的是,组件的生命周期钩子会被注册到组件实例上,并且使用了别名(枚举值),这里的 instance.bm 其实就是 beforeMount 钩子,instance.m 其实就是 mounted 钩子,instance.a 其实就是 activated 钩子。 所以,我们可以看出,生命周期钩子的调用顺序为:beforeMount -> mounted -> activated

卸载组件

unmountComponent.png unmount.png deactivate.png

这一部分,我们直接快进到 unmountComponent 函数,这里需要说明的是,这里的 bum 其实就是 beforeUnmount 钩子,um 其实就是 unmounted 钩子,instance.da 其实就是 deactivated 钩子。 所以,我们可以看出,生命周期钩子的调用顺序为:beforeUnmount -> deactivated -> unmounted