vue3生命周期执行时序

82 阅读1分钟

问题原因分析

typescript
import { onMounted, ref } from 'vue';

export default {
  setup() {
    const data = ref(null);
    
    // 异步获取数据
    fetchData().then(res => {
      data.value = res;
    });
    
    onMounted(() => {
      // 这里获取不到数据!
      console.log(data.value); // null
    });
    
    return { data };
  }
}

问题核心在于 执行时序

  1. setup 函数是同步执行
  2. 异步请求需要时间(网络请求通常是几十毫秒到几秒)
  3. onMounted 在组件挂载后立即执行(此时异步请求可能尚未完成)

正确解决方案

方案1:在 onMounted 中发起请求(推荐)

typescript
import { onMounted, ref } from 'vue';

export default {
  setup() {
    const data = ref(null);
    
    onMounted(async () => {
      // 确保在挂载后才发起请求
      data.value = await fetchData();
      // 此时可以安全使用数据
      console.log(data.value);
    });
    
    return { data };
  }
}

方案2:使用 watch 监听数据变化

typescript
import { onMounted, ref, watch } from 'vue';

export default {
  setup() {
    const data = ref(null);
    
    // 在setup中发起请求
    fetchData().then(res => {
      data.value = res;
    });
    
    // 监听数据变化
    watch(data, (newVal) => {
      if (newVal) {
        // 数据到达后执行操作
        console.log('数据已加载:', newVal);
      }
    });
    
    onMounted(() => {
      // 直接显示加载状态
      console.log('组件已挂载,等待数据...');
    });
    
    return { data };
  }
}

方案3:使用异步生命周期钩子(高级)

typescript
import { onMounted, ref } from 'vue';

export default {
  async setup() {
    const data = ref(null);
    
    // 在setup中发起请求但等待结果
    data.value = await fetchData();
    
    onMounted(() => {
      // 此时数据已准备就绪
      console.log(data.value);
    });
    
    return { data };
  }
}

生命周期执行时序图

组件初始化
  │
  ├─> setup() 同步执行
  │   │
  │   ├─> 发起异步请求(未完成)
  │   │
  │   └─> 注册 onMounted 回调
  │
  ├─> 模板编译/挂载
  │
  └─> onMounted() 执行
      │
      │  ❌ 此时数据尚未返回
      │
      ├─> 100ms后 异步请求完成 → 数据更新
      │
      └─> 触发重新渲染