在 Vue 3 的 Composition API 中,生命周期钩子的调用方式与 Options API 有显著不同。这种变化带来了更灵活的代码组织方式,同时也需要开发者适应新的语法模式。本文将详细介绍如何在 Composition API 中正确使用生命周期钩子。
一、生命周期钩子的变化背景
Vue 2 的 Options API 将生命周期钩子作为组件选项的固定属性:
1export default {
2 created() {
3 console.log('组件创建');
4 },
5 mounted() {
6 console.log('组件挂载');
7 }
8}
9
而 Vue 3 的 Composition API 将生命周期钩子转换为可导入的函数,这种设计使得:
- 逻辑可以更灵活地组织
- 更好的 TypeScript 支持
- 更清晰的代码结构
- 更容易的逻辑复用
二、Composition API 中的生命周期钩子
1. 基本导入方式
所有生命周期钩子都作为函数从 vue 包中导入:
1import {
2 onBeforeMount,
3 onMounted,
4 onBeforeUpdate,
5 onUpdated,
6 onBeforeUnmount,
7 onUnmounted,
8 onActivated,
9 onDeactivated,
10 onErrorCaptured
11} from 'vue';
12
2. 常用钩子示例
组件挂载前 (onBeforeMount)
1import { onBeforeMount } from 'vue';
2
3export default {
4 setup() {
5 onBeforeMount(() => {
6 console.log('组件即将挂载');
7 // 这里可以执行一些初始化操作
8 });
9 }
10}
11
组件挂载后 (onMounted)
1import { onMounted, ref } from 'vue';
2
3export default {
4 setup() {
5 const data = ref(null);
6
7 onMounted(() => {
8 console.log('组件已挂载');
9 // 通常在这里执行数据获取操作
10 fetchData().then(res => {
11 data.value = res;
12 });
13 });
14
15 return { data };
16 }
17}
18
组件更新前 (onBeforeUpdate)
1import { onBeforeUpdate, ref } from 'vue';
2
3export default {
4 setup() {
5 const count = ref(0);
6
7 onBeforeUpdate(() => {
8 console.log('组件即将更新', count.value);
9 });
10
11 return { count };
12 }
13}
14
组件更新后 (onUpdated)
1import { onUpdated, ref } from 'vue';
2
3export default {
4 setup() {
5 const count = ref(0);
6
7 onUpdated(() => {
8 console.log('组件已更新', count.value);
9 // 注意:避免在这里修改状态,可能导致无限更新循环
10 });
11
12 return { count };
13 }
14}
15
组件卸载前 (onBeforeUnmount)
1import { onBeforeUnmount, ref, onMounted } from 'vue';
2
3export default {
4 setup() {
5 const timer = ref(null);
6
7 onMounted(() => {
8 timer.value = setInterval(() => {
9 console.log('定时器运行中');
10 }, 1000);
11 });
12
13 onBeforeUnmount(() => {
14 clearInterval(timer.value);
15 console.log('清理定时器');
16 });
17 }
18}
19
组件卸载后 (onUnmounted)
1import { onUnmounted } from 'vue';
2
3export default {
4 setup() {
5 onUnmounted(() => {
6 console.log('组件已卸载');
7 // 执行清理操作
8 });
9 }
10}
11
三、与 Options API 的对比
| Options API | Composition API |
|---|---|
| beforeCreate | 不需要,setup() 本身就是 beforeCreate 之前执行 |
| created | 不需要,setup() 本身就是 created 之前执行 |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeUnmount | onBeforeUnmount |
| unmounted | onUnmounted |
| activated | onActivated |
| deactivated | onDeactivated |
| errorCaptured | onErrorCaptured |
四、最佳实践
1. 逻辑分组
将相关的生命周期钩子组织在一起:
1import { onMounted, onUnmounted } from 'vue';
2
3export default {
4 setup() {
5 // 数据获取相关逻辑
6 onMounted(() => {
7 fetchData();
8 });
9
10 // 清理相关逻辑
11 onUnmounted(() => {
12 cleanup();
13 });
14 }
15}
16
2. 自定义组合函数
可以创建自定义组合函数来封装常见模式:
1// useFetch.js
2import { onMounted, ref } from 'vue';
3
4export function useFetch(url) {
5 const data = ref(null);
6 const error = ref(null);
7
8 const fetchData = async () => {
9 try {
10 const response = await fetch(url);
11 data.value = await response.json();
12 } catch (err) {
13 error.value = err;
14 }
15 };
16
17 onMounted(fetchData);
18
19 return { data, error, fetchData };
20}
21
22// 在组件中使用
23import { useFetch } from './useFetch';
24
25export default {
26 setup() {
27 const { data, error } = useFetch('https://api.example.com/data');
28 return { data, error };
29 }
30}
31
3. 避免在 onUpdated 中修改状态
在 onUpdated 中修改状态会导致无限更新循环:
1// 错误示例
2onUpdated(() => {
3 count.value++; // 这会触发再次更新
4});
5
4. 服务器端渲染 (SSR) 注意事项
在 SSR 环境中,某些生命周期钩子(如 onMounted)只会在客户端执行,确保你的代码能够处理这种差异。
五、常见问题解答
1. 为什么没有 beforeCreate 和 created 钩子?
在 Composition API 中,setup() 函数本身就在 beforeCreate 和 created 钩子之间执行,所以不需要这两个钩子。任何在 setup() 中定义的响应式数据或方法都已经可用。
2. 如何在 Composition API 中访问组件实例?
Composition API 设计上避免了直接访问组件实例。如果需要访问 DOM 元素,可以使用 ref 模板引用:
1import { ref, onMounted } from 'vue';
2
3export default {
4 setup() {
5 const elementRef = ref(null);
6
7 onMounted(() => {
8 console.log(elementRef.value); // 访问 DOM 元素
9 });
10
11 return { elementRef };
12 }
13}
14
3. 如何监听路由变化?
使用 Vue Router 的 onBeforeRouteUpdate 导航守卫:
1import { onBeforeRouteUpdate } from 'vue-router';
2
3export default {
4 setup() {
5 onBeforeRouteUpdate((to, from, next) => {
6 console.log('路由即将更新');
7 next();
8 });
9 }
10}
11
六、总结
Vue 3 的 Composition API 通过将生命周期钩子转换为可导入的函数,提供了更灵活的代码组织方式。这种变化虽然需要一些适应时间,但带来了以下优势:
- 更清晰的逻辑组织
- 更好的 TypeScript 支持
- 更方便的逻辑复用
- 更一致的代码风格
掌握 Composition API 中的生命周期钩子使用方式,是充分利用 Vue 3 新特性的关键一步。随着实践的深入,你会发现这种模式能够编写出更模块化、更易维护的组件代码。