Nuxt3如何优雅暴露onMounted内useApi返回的状态变量
问题原因
你遇到的作用域错误本质是违反了Vue3组合式API的调用规则:将组合式函数useApi放在了onMounted的回调局部作用域内调用,解构得到的pending/data等变量自然无法被外部的组件上下文访问。
同时你封装的useApi底层返回的是Nuxt内置的useLazyFetch,本身就支持手动控制请求触发时机,完全不需要把整个调用逻辑塞进onMounted里。
最优实现方案
核心思路是:在setup顶层调用useApi拿到所有响应式返回值,关闭自动发起请求配置,等组件挂载完成后再手动触发请求,既解决作用域问题,又满足「挂载后才发请求」的时序要求。
1. 修正组件内调用逻辑
<script setup lang="ts"> // 顶层调用组合式函数,所有返回值天然在组件作用域可访问 // 传入immediate:false 关闭自动请求 const { data, refresh, pending, error } = await useApi(`/profile/${$auth.user.profile.sid}`, { immediate: false }, ['data']); // 直接访问顶层的pending,不存在作用域问题 const computedWaiting = computed<boolean>(() => { return pending.value === true; }); // 挂载完成后手动触发请求,完全符合时序要求 onMounted(() => { refresh() }); </script>
2. 修正useApi的类型定义(可选但推荐)
你当前封装的useApi的options类型只引用了ohmyfetch原生的FetchOptions,没有包含Nuxt useFetch扩展的immediate/watch等配置项,会导致TS类型报错,调整下类型定义即可:
// 引入Nuxt的UseFetchOptions类型兼容扩展配置 import type { UseFetchOptions } from 'nuxt/app' import { FetchOptions } from "ohmyfetch"; const csrf_cookie: string = "XSRF-TOKEN"; /** * 获取Sanctum需要的Cookie,浏览器自动处理 */ export const useFetchCookies = async () => { await $fetch.raw("/backend/sanctum/csrf-cookie", { credentials: "include" }); }; /** * 封装通用Api请求方法 */ export const useApi = async <T = any>(url: string, options?: UseFetchOptions<T>, pick?: any) => { let token = useCookie(csrf_cookie)?.value; if (!token) { await useFetchCookies(); token = useCookie(csrf_cookie).value; } const headers: HeadersInit = { Accept: "application/json", "Cache-Control": "no-cache", "X-XSRF-TOKEN": token, ...options?.headers }; const opts: UseFetchOptions<T> = options ? (({headers, ...opts}) => opts)(options) : null; return useLazyFetch<T>(`/backend/api${url}`, { server: false, credentials: "include", headers, ...opts, pick: pick }); };
不推荐的反模式说明
如果强行把useApi放在onMounted里,你需要手动在组件顶层声明所有对应的ref,在回调里做值同步:
// 冗余的顶层ref声明 const data = ref(null) const pending = ref(false) const error = ref(null) const refresh = ref(() => {}) onMounted(async() => { const res = await useApi(`/profile/${$auth.user.profile.sid}`, null, ['data']); // 手动同步每一个返回值 data.value = res.data.value pending.value = res.pending.value error.value = res.error.value refresh.value = res.refresh }); const computedWaiting = computed<boolean>(() => { return pending.value === true; });
这种写法会产生大量冗余代码,容易出现值同步遗漏、类型推导失效的问题,完全不符合组合式API的设计初衷。
内容的提问来源于stack exchange,提问作者SPQRInc
相关产品推荐
相关产品推荐

