父子组件与组件里 Hooks 加载顺序
Vue3 父子组件加载顺序
在 Vue3 中,父子组件的生命周期执行顺序如下:
挂载阶段 (Mounting):
- 父组件 setup()
- 父组件 onBeforeMount
- 子组件 setup()
- 子组件 onBeforeMount
- 子组件 onMounted
- 父组件 onMounted
更新阶段 (Updating):
- 父组件 onBeforeUpdate
- 子组件 onBeforeUpdate
- 子组件 onUpdated
- 父组件 onUpdated
卸载阶段 (Unmounting):
- 父组件 onBeforeUnmount
- 子组件 onBeforeUnmount
- 子组件 onUnmounted
- 父组件 onUnmounted
示例代码:
<!-- ParentComponent.vue -->
<template>
<div>
<h2>父组件</h2>
<ChildComponent />
</div>
</template>
<script setup>
import {
onMounted,
onBeforeMount,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
} from "vue";
import ChildComponent from "./ChildComponent.vue";
console.log("父组件 setup");
onBeforeMount(() => {
console.log("父组件 onBeforeMount");
});
onMounted(() => {
console.log("父组件 onMounted");
});
onBeforeUpdate(() => {
console.log("父组件 onBeforeUpdate");
});
onUpdated(() => {
console.log("父组件 onUpdated");
});
onBeforeUnmount(() => {
console.log("父组件 onBeforeUnmount");
});
onUnmounted(() => {
console.log("父组件 onUnmounted");
});
</script>
<!-- ChildComponent.vue -->
<template>
<div>
<h3>子组件</h3>
</div>
</template>
<script setup>
import {
onMounted,
onBeforeMount,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
} from "vue";
console.log("子组件 setup");
onBeforeMount(() => {
console.log("子组件 onBeforeMount");
});
onMounted(() => {
console.log("子组件 onMounted");
});
onBeforeUpdate(() => {
console.log("子组件 onBeforeUpdate");
});
onUpdated(() => {
console.log("子组件 onUpdated");
});
onBeforeUnmount(() => {
console.log("子组件 onBeforeUnmount");
});
onUnmounted(() => {
console.log("子组件 onUnmounted");
});
</script>
控制台输出顺序(挂载阶段):
父组件 setup
父组件 onBeforeMount
子组件 setup
子组件 onBeforeMount
子组件 onMounted
父组件 onMounted
Composition API 中的 Hooks 执行顺序
在 Vue3 的组件中,Composition API 的执行顺序如下:
- setup() 函数最先执行
- ref/reactive 声明的响应式数据初始化
- watch/watchEffect 监听器建立
- 生命周期钩子按照上述顺序执行
示例:
<script setup>
import { ref, reactive, watch, watchEffect, onMounted } from "vue";
console.log("1. setup 开始执行");
const count = ref(0);
console.log("2. ref 初始化");
const state = reactive({
message: "Hello",
});
console.log("3. reactive 初始化");
watch(count, (newVal, oldVal) => {
console.log("count 发生变化", newVal, oldVal);
});
console.log("4. watch 设置完成");
watchEffect(() => {
console.log("5. watchEffect 首次执行", count.value);
});
onMounted(() => {
console.log("6. onMounted 执行");
count.value++; // 这将触发 watch 和 watchEffect
});
</script>
这个示例展示了在一个组件中各种 Composition API 特性的执行顺序,包括响应式数据的初始化、监听器的建立以及生命周期钩子的触发顺序。
Hooks 的执行时机
Hooks 是在组件的setup()
函数中执行的,而setup()
函数是最早执行的。具体顺序是:
组件实例创建前,执行
setup()
函数在
setup()
函数内部,hooks 的执行顺序是:首先执行所有的
import
导入的 hooks然后按照代码书写顺序从上到下执行自定义 hooks
最后执行生命周期相关的 hooks(如
onMounted
等)
示例:
<script setup>
import { useUserInfo } from "@/hooks/useUserInfo"; // 第1步:导入的hooks
import { useRouter } from "vue-router";
console.log("setup开始");
const userInfo = useUserInfo(); // 第2步:执行导入的hooks
const router = useRouter();
const useCustomHook = () => {
// 第3步:执行自定义hooks
console.log("自定义hook执行");
return {};
};
const customData = useCustomHook();
onMounted(() => {
// 第4步:生命周期hooks
console.log("onMounted执行");
});
</script>
父子组件中 Hooks 的执行顺序
当涉及父子组件时,hooks 的执行遵循组件的生命周期顺序:
- 父组件 setup() 中的 hooks
- 父组件 onBeforeMount 中的 hooks
- 子组件 setup() 中的 hooks
- 子组件 onBeforeMount 中的 hooks
- 子组件 onMounted 中的 hooks
- 父组件 onMounted 中的 hooks
需要注意的是:
- 在同一个生命周期内的 hooks,会按照代码书写顺序执行
- 异步的 hooks(如包含
await
的 hooks)可能会影响实际的执行顺序 - 应该避免在 hooks 之间产生复杂的依赖关系,保持 hooks 的独立性