You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nuxt3中多次调用useFetch触发实例访问错误求助

解决Nuxt中多个useFetch调用触发实例访问错误的问题

错误原因

你遇到的报错是因为Nuxt的useFetch这类composable必须在Vue setup函数的同步执行阶段、Nuxt插件/钩子/中间件中调用。而你将useFetch放在嵌套的异步函数里,通过await链式调用init(),导致第二个useFetch执行时,已经脱离了setup的同步上下文,无法访问Nuxt实例。

解决方案

方案1:顶层await + Promise.all并行请求(推荐)

直接在<script setup>顶层并行发起两个API请求,避免嵌套异步导致的上下文丢失,同时提升请求效率:

<script setup>
// 通用状态
const alreadyCheckedIn = ref(false);
const showModal = ref(false);
const lecture = ref(null);

// 弹窗状态
const lectureName = ref("");
const startTime = ref("");

// 错误处理
const displayError = ref(false);
const errorMessage = ref("Please fill in all fields.");

const lectureDateStr = new Date().toISOString().split("T")[0];

// 并行发起两个请求
const [lectureRes, checkInRes] = await Promise.all([
  useFetch("/api/lecture", {
    method: "GET",
    query: {
      lectureDate: lectureDateStr,
      groupId: 1, // TODO: 从用户信息获取groupId
    },
  }),
  useFetch("/api/check-in", {
    method: "GET",
    query: {
      lectureDate: lectureDateStr,
      userId: 1, // TODO: 从用户信息获取userId
      groupId: 1, // TODO: 从用户信息获取groupId
    },
  })
]);

// 处理课程数据
if (lectureRes.data.value && lectureRes.data.value.statusCode !== 404) {
  lecture.value = JSON.parse(lectureRes.data.value.body);
  lecture.value.start_time = new Date(lecture.value.start_time)
    .toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" });
}

// 处理签到状态
alreadyCheckedIn.value = checkInRes.data.value && checkInRes.data.value.statusCode !== 404;
</script>

方案2:保留函数封装,提前调用useFetch

如果需要保留原有函数封装的结构,可以在setup顶层先调用useFetch,再将数据处理逻辑封装到函数中:

<script setup>
// 通用状态
const alreadyCheckedIn = ref(false);
const showModal = ref(false);
const lecture = ref(null);

// 弹窗状态
const lectureName = ref("");
const startTime = ref("");

// 错误处理
const displayError = ref(false);
const errorMessage = ref("Please fill in all fields.");

const lectureDateStr = new Date().toISOString().split("T")[0];

// 在setup顶层调用useFetch,确保上下文有效
const { data: lectureData } = useFetch("/api/lecture", {
  method: "GET",
  query: {
    lectureDate: lectureDateStr,
    groupId: 1, // TODO: 从用户信息获取groupId
  },
});

const { data: checkInData } = useFetch("/api/check-in", {
  method: "GET",
  query: {
    lectureDate: lectureDateStr,
    userId: 1, // TODO: 从用户信息获取userId
    groupId: 1, // TODO: 从用户信息获取groupId
  },
});

// 封装课程数据处理逻辑
function processLectureData() {
  if (!lectureData.value || lectureData.value.statusCode === 404) return;
  lecture.value = JSON.parse(lectureData.value.body);
  lecture.value.start_time = new Date(lecture.value.start_time)
    .toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" });
}

// 封装签到状态处理逻辑
function processCheckInStatus() {
  alreadyCheckedIn.value = checkInData.value && checkInData.value.statusCode !== 404;
}

// 监听数据变化,立即执行处理逻辑
watch(lectureData, processLectureData, { immediate: true });
watch(checkInData, processCheckInStatus, { immediate: true });
</script>

方案3:用onMounted包裹初始化函数

如果必须保留原有init函数的结构,可将init的调用放在onMounted钩子中,确保composable在Vue生命周期上下文内执行:

<script setup>
import { onMounted } from 'vue';

// 通用状态
const alreadyCheckedIn = ref(false);
const showModal = ref(false);
const lecture = ref(null);

// 弹窗状态
const lectureName = ref("");
const startTime = ref("");

// 错误处理
const displayError = ref(false);
const errorMessage = ref("Please fill in all fields.");

// 获取课程数据
async function fetchLectureData() {
  const lectureDateStr = new Date().toISOString().split("T")[0];
  const { data } = await useFetch("/api/lecture", {
    method: "GET",
    query: {
      lectureDate: lectureDateStr,
      groupId: 1, // TODO: 从用户信息获取groupId
    },
  });

  if (data.value.statusCode === 404) {
    return;
  }
  return data.value.body ? await JSON.parse(data.value.body) : null;
}

// 检查签到状态
async function checkIfCheckedIn() {
  const lectureDateStr = new Date().toISOString().split("T")[0];
  const { data } = await useFetch("/api/check-in", {
    method: "GET",
    query: {
      lectureDate: lectureDateStr,
      userId: 1, // TODO: 从用户信息获取userId
      groupId: 1, // TODO: 从用户信息获取groupId
    },
  });

  if (data.value.statusCode === 404) {
    return false;
  }
  return true;
}

// 初始化逻辑
async function init() {
  const lectureFromDB = await fetchLectureData();
  if (lectureFromDB) {
    lecture.value = lectureFromDB;
    lecture.value.start_time = new Date(lecture.value.start_time)
      .toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" });
  }
  alreadyCheckedIn.value = await checkIfCheckedIn();
}

// 在组件挂载后执行初始化
onMounted(init);
</script>

内容的提问来源于stack exchange,提问作者Julius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 18:45:55