一、组合式API带来的新变化
在Vue3中,最引人注目的变化莫过于组合式API(Composition API)的引入。这就像是从传统的"选项式"厨房升级到了现代化的"模块化"厨房,让我们可以更灵活地组织和复用代码逻辑。
想象一下,以前我们做菜(写组件)时,所有食材(数据)和厨具(方法)都分散在不同的抽屉(options)里。现在我们可以把相关的食材和厨具放在同一个料理台(setup函数)上,做菜效率自然就提高了。
// 技术栈:TypeScript + Vue3
import { ref, onMounted } from 'vue'
export default {
setup() {
// 定义响应式数据(相当于data选项)
const count = ref(0)
// 定义方法(相当于methods选项)
const increment = () => {
count.value++
}
// 生命周期钩子(相当于mounted选项)
onMounted(() => {
console.log('组件挂载完成啦!')
})
// 暴露给模板使用
return {
count,
increment
}
}
}
二、生命周期钩子的映射关系
Vue3的生命周期钩子在使用方式上有了很大变化,但核心思想没变。就像手机从按键式升级到触屏式,操作方式变了,但打电话、发短信的功能还在。
这里有个完整的映射表:
| Vue2选项式API | Vue3组合式API |
|---|---|
| beforeCreate | 不需要(setup替代) |
| created | 不需要(setup替代) |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeUnmount | onBeforeUnmount |
| unmounted | onUnmounted |
| activated | onActivated |
| deactivated | onDeactivated |
| errorCaptured | onErrorCaptured |
让我们看个完整示例:
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
export default {
setup() {
// 组件即将挂载
onBeforeMount(() => {
console.log('准备上车啦!')
})
// 组件已挂载
onMounted(() => {
console.log('已经坐稳了,可以发车了!')
})
// 组件即将更新
onBeforeUpdate(() => {
console.log('注意!数据要变啦!')
})
// 组件已更新
onUpdated(() => {
console.log('数据更新完成,界面已刷新')
})
// 组件即将卸载
onBeforeUnmount(() => {
console.log('准备下车了,别忘带东西!')
})
// 组件已卸载
onUnmounted(() => {
console.log('拜拜了您嘞~')
})
}
}
三、执行时机与使用技巧
理解生命周期钩子的执行时机非常重要,这就像知道火车时刻表一样,错过了就得等下一班。下面我们通过一个实际场景来演示:
import { ref, onMounted, onUpdated } from 'vue'
export default {
setup() {
const userList = ref<string[]>([])
const loading = ref(false)
// 模拟异步获取用户数据
const fetchUsers = async () => {
loading.value = true
try {
// 这里假设调用API获取数据
const response = await fetch('/api/users')
userList.value = await response.json()
} finally {
loading.value = false
}
}
// 组件挂载后立即获取数据
onMounted(fetchUsers)
// 当userList更新时执行某些操作
onUpdated(() => {
if (userList.value.length > 0) {
console.log('用户列表已更新,当前用户数:', userList.value.length)
}
})
return {
userList,
loading
}
}
}
在这个例子中,我们需要注意几个关键点:
onMounted是最常用的钩子,适合执行初始化操作,比如获取数据、设置定时器等onUpdated会在每次数据变化导致DOM更新后触发,但要小心避免无限循环- 异步操作最好配合
ref或reactive使用,确保响应式更新
四、常见问题与最佳实践
在实际开发中,我们经常会遇到一些生命周期相关的问题。下面列举几个典型场景:
场景一:在setup中访问DOM元素
import { ref, onMounted } from 'vue'
export default {
setup() {
const root = ref<HTMLElement | null>(null)
onMounted(() => {
// 只有在mounted后才能访问DOM元素
console.log('根元素宽度:', root.value?.offsetWidth)
})
return {
root
}
}
}
场景二:清理副作用
import { onMounted, onUnmounted } from 'vue'
export default {
setup() {
let timer: number
onMounted(() => {
timer = setInterval(() => {
console.log('定时器运行中...')
}, 1000)
})
onUnmounted(() => {
// 组件卸载时清除定时器
clearInterval(timer)
})
}
}
场景三:多个同类钩子的执行顺序
import { onMounted } from 'vue'
export default {
setup() {
// 多个同类型钩子会按照注册顺序执行
onMounted(() => {
console.log('第一个mounted钩子')
})
onMounted(() => {
console.log('第二个mounted钩子')
})
}
}
最佳实践建议:
- 将相关的生命周期逻辑组织在一起
- 清理工作一定要在
onUnmounted中进行 - 避免在
onUpdated中修改状态,可能导致无限循环 - 对于复杂组件,可以考虑使用自定义hook来封装生命周期逻辑
五、与Vue2的对比与迁移
对于从Vue2迁移过来的开发者,理解新旧生命周期的对应关系很重要。Vue3中:
beforeCreate和created被setup函数替代beforeDestroy和destroyed更名为beforeUnmount和unmounted- 所有钩子都需要显式导入并使用
迁移示例:
// Vue2写法
export default {
data() {
return {
count: 0
}
},
created() {
console.log('组件创建完成')
},
mounted() {
console.log('组件挂载完成')
},
beforeDestroy() {
console.log('组件即将销毁')
}
}
// Vue3等效写法
import { ref, onMounted, onBeforeUnmount } from 'vue'
export default {
setup() {
const count = ref(0)
console.log('组件创建完成') // 直接写在setup中相当于created
onMounted(() => {
console.log('组件挂载完成')
})
onBeforeUnmount(() => {
console.log('组件即将销毁')
})
return {
count
}
}
}
六、高级应用场景
对于更复杂的场景,比如需要在路由变化时重用组件,我们可以结合onActivated和onDeactivated来实现:
import { onActivated, onDeactivated } from 'vue'
export default {
setup() {
// 当使用<keep-alive>缓存组件时
onActivated(() => {
console.log('组件被激活')
// 可以在这里刷新数据
})
onDeactivated(() => {
console.log('组件被停用')
// 可以在这里暂停视频播放等
})
}
}
另一个常见场景是错误处理:
import { onErrorCaptured } from 'vue'
export default {
setup() {
onErrorCaptured((err, instance, info) => {
console.error('捕获到子组件错误:', err)
// 可以在这里上报错误
return false // 阻止错误继续向上传播
})
}
}
七、总结与建议
通过本文的讲解,相信大家对Vue3组合式API中的生命周期有了更深入的理解。总结几个关键点:
- 组合式API让生命周期逻辑更集中,便于维护
- 所有钩子都需要从vue中显式导入
setup函数替代了beforeCreate和created- 清理工作务必在
onUnmounted中进行 - 对于缓存组件,可以使用
onActivated和onDeactivated
在实际项目中,建议:
- 将复杂的生命周期逻辑封装成自定义hook
- 注意内存泄漏问题,及时清理定时器、事件监听等
- 合理使用
onUpdated,避免性能问题 - 结合TypeScript可以获得更好的类型提示
评论