Nuxt 3中nuxt instance unavailable错误排查与修复求助
错误日志
Error: nuxt instance unavailable 10:42:04 at Module.useNuxtApp (/Users/chilperic/Sites/cabinetpartage/node_modules/nuxt/dist/app/nuxt.mjs:165:13) at Module.useAsyncData (/Users/chilperic/Sites/cabinetpartage/node_modules/nuxt/dist/app/composables/asyncData.mjs:24:38) at Module.useFetch (/Users/chilperic/Sites/cabinetpartage/node_modules/nuxt/dist/app/composables/fetch.mjs:52:43) at Module.__vite_ssr_exports__.default (/Users/chilperic/Sites/cabinetpartage/composables/useUsers.ts:6:55) at Module.__vite_ssr_exports__.default (/Users/chilperic/Sites/cabinetpartage/composables/useRoomAvailability.ts:61:55) at processTicksAndRejections (node:internal/process/task_queues:96:5) at async setup (/Users/chilperic/Sites/cabinetpartage/pages/salles/[idLocation]/[idRoom].vue:59:12)
页面调用代码
try { const roomAvailability = await useRoomAvailability(route.params.idRoom); } catch (e) { console.log(e); }
组合式函数代码
class RoomSchedule { roomId: String = ""; days = [ "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday", ]; monday = []; tuesday = []; wednesday = []; thursday = []; friday = []; saturday = []; sunday = []; constructor(roomId: String) { this.roomId = roomId; } checkAvailability(profile) { for (let d in this.days) { if ( profile.weekly_schedule[this.days[d]] !== false && profile.weekly_schedule[this.days[d]][this.roomId] !== undefined && profile.weekly_schedule[this.days[d]][this.roomId] == true ) { // 创建预约对象 const apt = { begins_at: "07:00", ends_at: "20:00", name: profile.first_name + " " + profile.last_name, job: profile.job, user: profile.user_id, }; // 去重 if ( this[this.days[d]].find( (element) => JSON.stringify(element) === JSON.stringify(apt) ) == undefined ) { this[this.days[d]].push({ begins_at: "07:00", ends_at: "20:00", name: profile.first_name + " " + profile.last_name, job: profile.job, user: profile.user_id, }); } } else { // console.log("rien pour " + this.days[d]); } } return true; } } export default async (roomId: String) => { // 获取房间可用性 const locationsObject = await useLocations(); const locations = Object.values({ ...locationsObject }); const room = locations.filter((el) => el.identifier == roomId); const roomAvailability = toRaw(room[0]).availability; let Schedule = new RoomSchedule(roomId); // 获取租户预约信息 const profiles = await useUsers(); for (let av in profiles) { // 遍历日期,检查租户预约 for (let day in profiles[av].weekly_schedule) { await Schedule.checkAvailability(profiles[av]); } } return Schedule; };
问题根源
从错误栈可定位核心问题:useUsers内部调用useFetch时无法获取Nuxt实例,本质是违反了Nuxt组合式函数调用规则:
useFetch/useAsyncData/useNuxtApp这类内置组合式函数,必须在setup生命周期的同步执行阶段调用,不能在异步函数的await之后、异步回调中调用,否则会丢失Nuxt实例上下文。useLocations和useUsers被写成async函数,内部用await包裹useFetch,导致在useRoomAvailability中await useLocations()/await useUsers()时,实际是在异步上下文里调用useFetch,触发实例不可用错误。- 额外问题:
checkAvailability是同步方法,无需用await调用,多余的await会加剧上下文混乱。
修复方案
步骤1:修正useLocations和useUsers的写法
不要用async/await包裹useFetch,直接返回响应式结果:
// composables/useUsers.ts export default () => { // useFetch返回响应式对象,无需await const { data: profiles, pending, error } = useFetch('/api/users') return { profiles, pending, error } }
同理修改useLocations.ts,保持一致写法。
步骤2:重构useRoomAvailability
用useAsyncData封装整个逻辑,确保所有组合式函数在同步阶段调用,同时处理响应式数据依赖:
// composables/useRoomAvailability.ts export default (roomId: string) => { // 在同步阶段调用组合式函数,获取响应式数据 const { data: locations } = useLocations() const { data: profiles } = useUsers() // 用useAsyncData处理依赖响应式数据的异步逻辑 const { data: schedule } = useAsyncData( `room-schedule-${roomId}`, // 唯一key用于缓存 async () => { // 等待依赖数据加载完成 if (!locations.value || !profiles.value) return null const room = locations.value.find(el => el.identifier === roomId) if (!room) return null const roomSchedule = new RoomSchedule(roomId) // 遍历租户数据,移除多余的await for (const profile of profiles.value) { roomSchedule.checkAvailability(profile) } return roomSchedule }, { // 当依赖项变化时自动重新执行 watch: [roomId, locations, profiles] } ) return schedule }
步骤3:修正页面调用逻辑
不需要await,直接使用响应式数据:
// pages/salles/[idLocation]/[idRoom].vue <script setup> const route = useRoute() const roomAvailability = useRoomAvailability(route.params.idRoom as string) // 可选:处理加载状态 const { pending } = useRoomAvailability(route.params.idRoom as string) </script>
额外优化建议
- 用
find替代filter[0],提升数组查找效率 - 避免用
JSON.stringify做对象比较,可改用唯一标识(比如user字段)去重,性能更优 - 类型定义中用
string替代String(小写是TS基础类型,大写是包装对象)
内容的提问来源于stack exchange,提问作者fxguillois
相关产品推荐
相关产品推荐

