Vue.js 生命周期深入解析
生命周期流程图
graph TD
A[创建组件实例] --> B[beforeCreate]
B --> C[created]
C --> D[beforeMount]
D --> E[mounted]
E --> F{数据更新?}
F -->|是| G[beforeUpdate]
G --> H[updated]
H --> F
F -->|否| I{组件卸载?}
I -->|是| J[beforeUnmount]
J --> K[unmounted]
L[keep-alive] --> M[activated]
L --> N[deactivated]
O[错误产生] --> P[errorCaptured]
错误处理
flowchart TD
A[子组件错误] --> B{errorCaptured}
B -->|返回true| C[向上传播]
B -->|返回false| D[停止传播]
C --> E[全局错误处理]
选项式 API (Options API)
选项式 API 是 Vue 传统的组织组件代码的方式。我们通过定义一个包含选项的对象来描述组件的逻辑,例如 data、methods 和 mounted 等选项。属性定义在组件选项中,使用 this 访问。
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
},
mounted() {
console.log('组件已挂载')
}
}组合式 API (Composition API)
组合式 API 是 Vue3 新增的一种组织组件代码的方式。它允许我们使用导入的 API 函数来描述组件逻辑。组件的代码是通过组合函数来组织的,通常在 setup 函数中编写。
import { ref, onMounted } from 'vue'
export default {
setup() {
const count = ref(0)
function increment() {
count.value++
}
onMounted(() => {
console.log('组件已挂载')
})
return {
count,
increment
}
}
}生命周期钩子对应关系
NOTE
Vue3提供两种编写方式,下表展示了它们的对应关系:
| 选项式 API | 组合式 API | 执行时机与用途 |
|---|---|---|
| beforeCreate | setup() | 组件实例初始化之前,此时无法访问数据和方法 |
| created | setup() | 组件实例创建完成,可以访问数据和方法,但还未挂载DOM |
| beforeMount | onBeforeMount() | 组件挂载之前,模板编译完成但还未渲染到页面 |
| mounted | onMounted() | 组件挂载完成,可以访问DOM,适合执行初始化操作 |
| beforeUpdate | onBeforeUpdate() | 数据更新时,DOM更新之前调用,适合在更新前访问现有DOM |
| updated | onUpdated() | DOM更新完成后调用,注意避免在此修改数据防止死循环 |
| beforeUnmount | onBeforeUnmount() | 组件卸载前调用,适合清理工作(定时器、事件监听等) |
| unmounted | onUnmounted() | 组件卸载完成后调用,组件完全销毁 |
| errorCaptured | onErrorCaptured() | 捕获后代组件错误,可以处理错误并阻止向上传播 |
| renderTracked | onRenderTracked() | 调试用:跟踪虚拟DOM重新渲染的依赖来源 |
| renderTriggered | onRenderTriggered() | 调试用:跟踪触发虚拟DOM重新渲染的依赖 |
| activated | onActivated() | keep-alive缓存的组件激活时调用 |
| deactivated | onDeactivated() | keep-alive缓存的组件停用时调用 |
| serverPrefetch | onServerPrefetch() | 服务端渲染期间调用,用于预获取数据 |
特别说明
setup函数的特殊性:- 在组件创建之前执行,因此替代了 beforeCreate 和 created
- 没有 this 上下文
- 返回的对象中的属性将暴露给模板使用
- 可以是异步函数(setup async)
调试钩子的使用场景:
onRenderTracked:- 跟踪组件首次渲染时的依赖收集
- 帮助理解哪些响应式数据被组件使用
onRenderTriggered:- 跟踪导致组件重新渲染的具体依赖
- 帮助排查性能问题和不必要的渲染
组合式 API 的最佳实践:
- 使用组合函数(Composables)抽取和复用逻辑
- 保持 setup 函数的简洁
- 合理使用生命周期钩子
- 注意及时清理副作用
- 使用 TypeScript 获得更好的类型支持
性能考虑:
- 组合式 API 通常能产生更好的 tree-shaking 效果
- 代码更容易被压缩
- 按需导入可以减少打包体积
挂载阶段钩子函数
挂载阶段
sequenceDiagram
participant App as 应用
participant VM as 虚拟DOM
participant DOM as 真实DOM
App->>VM: beforeMount
VM->>DOM: 创建DOM元素
DOM->>App: mounted
onBeforeMount 与 beforeMount
组件挂载到 DOM 之前被调用。此时模板已经编译完成,但还没有渲染到页面上。
// 选项式 API
export default {
beforeMount() {
console.log('组件即将挂载');
}
// 组合式 API
import { onBeforeMount } from 'vue';
setup() {
onBeforeMount(() => {
console.log('组件即将挂载');
})onMounted 与 mounted
组件挂载到 DOM 后调用。这是最常用的生命周期之一,通常用于: 访问或操作 DOM 发起初始化数据请求 添加事件监听器
// 选项式 API
export default {
mounted() {
console.log('组件已挂载');
this.fetchData();
}
}
// 组合式 API
import { onMounted } from 'vue';
setup() {
onMounted(() => {
console.log('组件已挂载');
fetchData();
})
}更新阶段钩子函数
onBeforeUpdate 与 beforeUpdate
数据发生改变后,DOM 被更新之前调用。适合在现有 DOM 将要被更新之前访问它。
// 选项式 API
export default {
beforeUpdate() {
console.log('DOM更新之前');
}
// 组合式 API
import { onBeforeUpdate } from 'vue';
setup() {
onBeforeUpdate(() => {
console.log('DOM更新之前');
})onUpdated 与 updated
数据更改导致的虚拟 DOM 重新渲染和打补丁之后调用。 意:不要在 updated 中修改数据,可能会导致无限循环。
// 选项式 API
export default {
updated() {
console.log('DOM更新完成');
}
// 组合式 API
import { onUpdated } from 'vue';
setup() {
onUpdated(() => {
console.log('DOM更新完成');
})卸载阶段钩子函数
onBeforeUnmount 与 beforeUnmount
组件卸载之前调用。这个阶段组件实例仍然完全可用。 用于: 清除定时器 取消事件监听 取消网络请求
// 选项式 API
export default {
beforeUnmount() {
console.log('组件即将卸载');
clearInterval(this.timer);
}
// 组合式 API
import { onBeforeUnmount } from 'vue';
setup() {
onBeforeUnmount(() => {
console.log('组件即将卸载');
clearInterval(timer);
})onUnmounted 与 unmounted
件卸载后调用。此时所有的子组件也都已经被卸载。
// 选项式 API
export default {
unmounted() {
console.log('组件已卸载');
}
// 组合式 API
import { onUnmounted } from 'vue';
setup() {
onUnmounted(() => {
console.log('组件已卸载');
})beforeDestroy 与 destroyed
是 Vue 2.x 的生命周期函数,在 Vue 3 中已被重命名为 beforeUnmount 和 unmounted。
错误处理钩子函数
onErrorCaptured 与 errorCaptured
捕获到后代组件的错误时调用。可以返回 false 以阻止错误继续向上传播。
// 选项式 API
export default {
errorCaptured(err, instance, info) {
console.log('捕获到错误:', err);
return false; // 阻止错误继续传播
}
// 组合式 API
import { onErrorCaptured } from 'vue';
setup() {
onErrorCaptured((err, instance, info) => {
console.log('捕获到错误:', err);
return false;
})调试钩子函数
onRenderTracked 与 renderTracked
试用的钩子,当组件渲染过程中追踪到响应式依赖时调用。
setup() {
onRenderTracked((event) => {
console.log('响应式依赖被追踪:', event);
})onRenderTriggered 与 renderTriggered
试用的钩子,当响应式依赖触发组件重新渲染时调用。
setup() {
onRenderTriggered((event) => {
console.log('触发组件重新渲染:', event);
})keep-alive 相关钩子函数
onActivated 与 activated
keep-alive 缓存的组件激活时调用。
setup() {
onActivated(() => {
console.log('组件被激活');
})onDeactivated 与 deactivated
keep-alive 缓存的组件停用时调用。
setup() {
onDeactivated(() => {
console.log('组件被停用');
})服务端渲染钩子函数
onServerPrefetch 与 serverPrefetch
务端渲染期间,在实例渲染之前调用。常用于确保服务端渲染时数据已准备就绪。
etup() {
onServerPrefetch(async () => {
// 在服务端渲染期间等待异步数据
await fetchServerData();
})实践建议
- 资源清理
- 在
beforeUnmount/onBeforeUnmount中清理:- 定时器 (clearTimeout/clearInterval)
- 事件监听器 (removeEventListener)
- DOM 观察器 (disconnect)
- 网络请求取消
- WebSocket 连接关闭
- 数据更新
- 避免在
updated/onUpdated中直接修改响应式数据 - 防止进入无限更新循环
- 如需修改,请使用计算属性或监听器
- 错误处理
- 合理使用
errorCaptured/onErrorCaptured捕获子组件错误 - 可以返回
false阻止错误继续向上传播 - 配合错误边界组件使用
- 性能优化
- 调试钩子 (
onRenderTracked/onRenderTriggered) 仅在开发环境使用 - 用于分析组件重新渲染的原因
- 帮助识别不必要的更新
- 缓存组件
- 使用
keep-alive时注意处理activated/onActivated钩子 - 可以在
deactivated/onDeactivated中暂停一些操作