Vue的生命周期钩子是组件开发中的重要概念,它们允许我们在组件的不同阶段执行特定的逻辑。本文将详细介绍Vue 3中常用的生命周期钩子,并结合实际例子展示其应用场景。
什么是生命周期钩子?
生命周期钩子是在组件从创建到销毁过程中自动调用的特殊函数。它们为我们提供了在特定时间点执行代码的机会。
主要生命周期钩子
1. onMounted - 组件挂载完成
当组件的DOM被渲染完成后调用,通常用于:
- 发起网络请求
- 操作DOM元素
- 初始化第三方库
js
<script setup>
import { ref, onMounted } from 'vue'
const userList = ref([])
onMounted(async () => {
// 组件挂载后加载用户数据
try {
const response = await fetch('/api/users')
userList.value = await response.json()
} catch (error) {
console.error('加载用户数据失败:', error)
}
})
</script>
2. onBeforeMount - 组件挂载前
在DOM渲染之前调用,此时还不能访问DOM元素:
js
<script setup>
import { ref, onBeforeMount } from 'vue'
const isLoading = ref(true)
onBeforeMount(() => {
// 在DOM渲染前做一些准备工作
console.log('组件即将挂载...')
isLoading.value = true
})
</script>
3. onBeforeUpdate - 数据更新前
在响应式数据改变后,DOM重新渲染前调用:
js
<script setup>
import { ref, onBeforeUpdate } from 'vue'
const count = ref(0)
const renderCount = ref(0)
onBeforeUpdate(() => {
// 每次更新前增加渲染计数
renderCount.value++
console.log(`组件即将第${renderCount.value}次更新`)
})
</script>
4. onUpdated - 数据更新后
在DOM重新渲染完成后调用:
js
<script setup>
import { ref, onUpdated } from 'vue'
const message = ref('Hello')
onUpdated(() => {
// DOM更新完成后可以访问最新的DOM
console.log('DOM已更新完成')
})
</script>
5. onBeforeUnmount - 组件卸载前
在组件卸载之前调用,用于清理工作:
js
<script setup>
import { ref, onBeforeUnmount } from 'vue'
let timer = null
// 启动定时器
timer = setInterval(() => {
console.log('定时任务执行中...')
}, 1000)
onBeforeUnmount(() => {
// 组件卸载前清除定时器
if (timer) {
clearInterval(timer)
timer = null
}
})
</script>
6. onUnmounted - 组件卸载后
在组件卸载完成后调用:
js
<script setup>
import { onUnmounted } from 'vue'
onUnmounted(() => {
// 组件完全卸载后的清理工作
console.log('组件已被卸载')
})
</script>
实际应用案例
完整的用户管理组件示例
js
<template>
<div class="user-management">
<h2>用户管理系统</h2>
<div v-if="loading">加载中...</div>
<ul v-else>
<li v-for="user in users" :key="user.id">
{{ user.name }} - {{ user.email }}
</li>
</ul>
<button @click="refreshData">刷新数据</button>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUpdate, onUnmounted } from 'vue'
const users = ref([])
const loading = ref(false)
const refreshCount = ref(0)
let pollingTimer = null
// 组件挂载时加载数据
onMounted(async () => {
console.log('用户管理组件已挂载')
await loadUsers()
// 启动轮询定时器
pollingTimer = setInterval(async () => {
await loadUsers()
}, 30000) // 每30秒刷新一次
})
// 更新前记录刷新次数
onBeforeUpdate(() => {
refreshCount.value++
console.log(`数据第${refreshCount.value}次更新`)
})
// 组件卸载前清理资源
onUnmounted(() => {
console.log('用户管理组件正在卸载')
if (pollingTimer) {
clearInterval(pollingTimer)
pollingTimer = null
}
})
// 加载用户数据
const loadUsers = async () => {
try {
loading.value = true
const response = await fetch('/api/users')
users.value = await response.json()
} catch (error) {
console.error('加载用户失败:', error)
} finally {
loading.value = false
}
}
// 手动刷新数据
const refreshData = () => {
loadUsers()
}
</script>
最佳实践建议
-
合理选择钩子时机
- 网络请求通常放在
onMounted - 资源清理放在
onBeforeUnmount - DOM操作避免在
onBeforeMount和onBeforeUpdate
- 网络请求通常放在
-
注意内存泄漏
- 及时清理定时器、事件监听器等
- 使用
onBeforeUnmount进行资源回收
-
异步操作处理
- 在组件卸载前取消未完成的异步请求
- 避免在已卸载组件上设置状态