生命周期钩子在 Composition API 中的使用
Vue 3 的 Composition API 将组件的生命周期管理整合到 setup 函数中,通过导入特定的生命周期钩子函数(如 onMounted、onUnmounted)实现与 Options API 相同的功能。与传统的选项式写法相比,这种方式更灵活,且能与函数式逻辑无缝结合。本节将详细讲解这些钩子的用法、与 Options API 的对应关系,并通过示例展示如何在 Composition API 中高效使用生命周期。
生命周期钩子简介
在 Vue 3 中,生命周期钩子是 Composition API 的一部分,它们以 on 开头的函数形式提供,例如 onMounted、onBeforeUpdate 等。这些钩子可以在 setup 函数中直接调用,用于执行组件生命周期中的特定逻辑。
与 Options API 的对应关系
| Options API | Composition API | 执行时机 |
|---|---|---|
beforeCreate | 无需(setup 替代) | 组件实例初始化前 |
created | 无需(setup 替代) | 组件实例创建后 |
beforeMount | onBeforeMount | DOM 挂载前 |
mounted | onMounted | DOM 挂载后 |
beforeUpdate | onBeforeUpdate | 数据更新前,DOM 未刷新 |
updated | onUpdated | 数据更新后,DOM 已刷新 |
beforeUnmount | onBeforeUnmount | 组件卸载前 |
unmounted | onUnmounted | 组件卸载后 |
- 注意:
beforeCreate和created被setup取代,因为setup在这两个阶段之间执行。
基本用法
生命周期钩子函数接受一个回调,在特定时机执行。
示例:基本生命周期
<template>
<div>
<p>{{ message }}</p>
<button @click="updateMessage">更新</button>
</div>
</template>
<script>
import { ref, onMounted, onBeforeUpdate, onUnmounted } from 'vue';
export default {
setup() {
const message = ref('初始消息');
// 组件挂载时执行
onMounted(() => {
console.log('组件已挂载');
message.value = '已挂载';
});
// 数据更新前执行
onBeforeUpdate(() => {
console.log('更新前:', message.value);
});
// 组件卸载时执行
onUnmounted(() => {
console.log('组件已卸载');
});
const updateMessage = () => {
message.value = '新消息';
};
return { message, updateMessage };
}
};
</script>
- 效果:
- 挂载时:控制台打印“组件已挂载”,显示“已挂载”。
- 点击按钮:打印“更新前: 已挂载”,然后更新为“新消息”。
- 组件销毁:打印“组件已卸载”。
在自定义 Hook 中的使用
生命周期钩子常与自定义 Hook 结合,用于管理副作用。
示例:鼠标位置跟踪 Hook
// src/composables/useMouse.js
import { ref, onMounted, onUnmounted } from 'vue';
export function useMouse() {
const x = ref(0);
const y = ref(0);
const updatePosition = (event) => {
x.value = event.clientX;
y.value = event.clientY;
};
onMounted(() => {
window.addEventListener('mousemove', updatePosition);
console.log('开始跟踪鼠标');
});
onUnmounted(() => {
window.removeEventListener('mousemove', updatePosition);
console.log('停止跟踪鼠标');
});
return { x, y };
}
使用
<template>
<div>
<p>鼠标位置:X: {{ x }}, Y: {{ y }}</p>
</div>
</template>
<script>
import { useMouse } from '@/composables/useMouse';
export default {
setup() {
const { x, y } = useMouse();
return { x, y };
}
};
</script>
- 效果:鼠标移动时更新位置,组件销毁时清理监听。
高级用法
1. 多次调用钩子
同一个钩子可以多次调用,按注册顺序执行。
<script>
import { onMounted } from 'vue';
export default {
setup() {
onMounted(() => console.log('挂载步骤 1'));
onMounted(() => console.log('挂载步骤 2'));
}
};
</script>
- 输出:
挂载步骤 1 挂载步骤 2
2. 动态条件执行
结合逻辑动态调用钩子。
<script>
import { ref, onUpdated } from 'vue';
export default {
setup() {
const count = ref(0);
const shouldLog = ref(true);
if (shouldLog.value) {
onUpdated(() => {
console.log('更新后:', count.value);
});
}
const increment = () => {
count.value++;
};
return { count, increment };
}
};
</script>
3. 与异步操作结合
在 onMounted 中执行异步任务。
<template>
<p>{{ data }}</p>
</template>
<script>
import { ref, onMounted } from 'vue';
export default {
setup() {
const data = ref(null);
onMounted(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
data.value = await response.json();
});
return { data };
}
};
</script>
- 效果:挂载后加载数据并显示。
与 Options API 的混合使用
生命周期钩子可以在两种 API 中共存:
<template>
<p>{{ message }}</p>
</template>
<script>
import { ref, onMounted } from 'vue';
export default {
data() {
return {
message: '初始'
};
},
mounted() {
console.log('Options API: 挂载');
},
setup() {
const count = ref(0);
onMounted(() => {
console.log('Composition API: 挂载');
this.message = '已挂载'; // 访问 Options 数据
});
return { count };
}
};
</script>
- 输出:
Composition API: 挂载 Options API: 挂载 - 注意:需谨慎管理
this,推荐统一使用一种方式。
注意事项
- 作用域:
- 钩子必须在
setup或自定义 Hook 中调用,不能在全局作用域使用。
onMounted(() => console.log('错误')); // 无效 - 钩子必须在
- 清理副作用:
- 使用
onUnmounted清理定时器、事件监听等,避免内存泄漏。
- 使用
- 执行顺序:
- 按照注册顺序执行,注意逻辑依赖。
综合示例
结合多个钩子实现动态列表:
<template>
<div>
<input v-model="newItem" @keyup.enter="addItem" />
<ul>
<li v-for="item in items" :key="item.id">{{ item.text }}</li>
</ul>
</div>
</template>
<script>
import { ref, reactive, onMounted, onBeforeUpdate, onUnmounted } from 'vue';
export default {
setup() {
const newItem = ref('');
const items = reactive([]);
const addItem = () => {
if (newItem.value.trim()) {
items.push({ id: Date.now(), text: newItem.value });
newItem.value = '';
}
};
onMounted(() => {
console.log('列表组件挂载');
});
onBeforeUpdate(() => {
console.log('列表即将更新,当前数量:', items.length);
});
const interval = setInterval(() => {
console.log('定时检查:', items.length);
}, 5000);
onUnmounted(() => {
clearInterval(interval);
console.log('组件销毁,清理定时器');
});
return { newItem, items, addItem };
}
};
</script>
- 效果:添加列表项,挂载、更新和销毁时打印日志,定时器自动清理。
总结
在 Composition API 中,生命周期钩子以函数形式提供,灵活嵌入 setup 或自定义 Hook 中。它们与 Options API 的功能一致,但在逻辑组织和复用性上有显著优势。掌握这些钩子的使用后,你可以更好地管理组件的生命周期和副作用。下一节将通过实战案例展示表单验证 Hook 的构建,进一步巩固你的技能!
