从零开始学Vue3:Vue3的生命周期
Vue3
与Vue2
的生命周期从总体上来看并没有太多的变化,所有我们在Vue2
的生命周期基础之上来讲述Vue3
的生命周期,如果不了解Vue2
的生命周期,可以先看看我的这篇文章:从零开始学Vue3:Vue2的生命周期
一、核心区别
1.1 钩子函数名称变化
Vue 3
为了与组合式 API
更好地对齐,并遵循更通用的命名约定,将两个钩子重命名了:
beforeDestroy
->beforeUnmount
destroyed
->unmounted
其余钩子(beforeCreate, created, beforeMount, mounted, beforeUpdate, updated
)均保持不变。
1.2 全新的使用方式:组合式 API
这是 Vue 3
最重大的变革。在 Vue 2
的选项式 API (Options API)
中,生命周期钩子是作为组件选项直接定义在对象中的。
在 Vue 3
的组合式 API
中,生命周期钩子必须在 setup() 函数
内部使用,并且是以导入的函数形式来调用。
Vue.js 提供了两种编写组件的主要风格:选项式 API 和组合式 API。选项式 API 通过像 data、methods 和 mounted 这样的独立选项来组织代码,结构清晰规整,非常易于初学者理解,但当组件变得复杂时,同一功能的代码会被拆分到不同选项,导致难以阅读和维护。而组合式 API 则允许开发者使用 ref、reactive 等函数按逻辑功能(而非选项类型)来组织代码,它将所有相关变量和函数都放在一起,使得复杂组件的逻辑更易于追踪和理解,并且天然提供了更优秀的代码复用能力。组合式 API 是 Vue 3 推荐的写法,它提供了更好的类型推断、更灵活的代码组织方式和更强大的复用性,尤其适合大型项目。
初始化(beforeCreate & created)
Vue 2 :有两个独立的钩子。beforeCreate
时什么都没有;created
时,数据和方法已可用,但 DOM 还未生成。
Vue 3 演变:这两个钩子被“融合”进了 setup()
函数本身。
当你进入
setup() 函数体
执行第一行代码时,就相当于处在Vue 2
的beforeCreate之后
、created 之前
的某个瞬间。此时,所有由ref
或reactive
定义的响应式数据已经初始化完毕。因此,在setup()
中任何顶层编写的代码,其执行时机都等价于 Vue 2 的 created 钩子。你可以直接操作响应式数据,进行 API 调用初始化等。
挂载(beforeMount & mounted)
Vue 2 :beforeMount
时模板已编译但还未转为真实 DOM
;mounted
时组件已完全挂载,可以安全操作 DOM
。
Vue 3:onBeforeMount 和 onMounted
的行为与 Vue 2
几乎完全一致。onMounted
是你进行 DOM
操作、启动定时器、订阅事件或发起异步请求的主要场所。
一个重要的细微差别:由于 Vue 3 支持碎片(
Fragments
),即组件可以有多个根节点。因此,当onMounted
被触发时,它只保证当前组件的DOM
已经就绪,并不能保证所有子组件也都被挂载。如果你需要操作子组件的DOM
或确保整个视图都已渲染,传统的this.$nextTick()
方法仍然是你的好朋友。
更新(beforeUpdate & updated)
Vue 2 :数据变化后,beforeUpdate
在 DOM 打补丁
之前触发,允许你在更新前获取 DOM 状态
;updated
在 DOM
重新渲染后触发。
Vue 3:这两个钩子的行为在 Vue 3
中没有变化。onUpdated
同样是一个需要极度谨慎使用的地方。因为任何在内部修改状态的操作都可能再次触发更新,导致无限的更新循环。
组合式 API
的优势在于,许多原本需要在这两个钩子里做的事情,现在可以通过watch
或watchEffect
来更优雅、更精确地完成。你可以直接响应状态的变化,而不必关心DOM 更新
的具体时机。
卸载(beforeUnmount & unmounted)
Vue 2 :beforeDestroy
时实例还完全可用;destroyed
时实例已被完全拆除。
Vue 3 :名称的变化是核心。onBeforeUnmount
和 onUnmounted
不仅仅是改名,更是为了更准确地描述过程。组件不是被“销毁”了,而是从 DOM
树上被“卸载”了。这是一个更精确的术语。
这里是资源清理的黄金时间。取消未完成的网络请求、清除定时器、解除自定义事件监听、关闭 WebSocket 连接等所有清理工作,都必须在此进行。这是防止内存泄漏的最重要关卡。组合式 API 鼓励将“创建”和“清理”的逻辑放在一起(都在 setup() 中),这使得代码更容易维护,你不会忘记在某个遥远的选项里还有一个需要清理的定时器。