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
中暂停一些操作