Nuxt3中await useAsyncData无法阻止导航,如何等待Store数据加载?
问题描述
使用Nuxt 3 + Supabase + Pinia技术栈,希望在Store数据获取并设置完成后再跳转到下一页。
当前实现代码:
- provider.vue(用户登录/注册后重定向页面,用于设置Cookie等):
// redirect once user has been set const user = useSupabaseUser() watch(user, async () => { if (user.value) { await useSteps().handleNavigateToNextStep() } }, { immediate: true })
- app.vue中尝试用
useAsyncData阻塞导航以获取Store数据:
const user = useSupabaseUser() await useAsyncData('userStoreData', async () => { if (user.value) { await useUserStore().fetchInitialData() } }, { watch: [user] })
- Pinia UserStore(简化版):
export const useUserStore = defineStore({ id: 'UserStore', state: () => ({ company: null as Tables<'company'> | null, }), actions: { async fetchInitialData() { const [companyData] = await Promise.all([ useCompany().getCompany(), ]) this.company = companyData; }, } })
遇到的问题:在provider.vue重定向后,通过const { company } = storeToRefs(useUserStore())获取的company值为undefined,需要让应用等待Store数据设置完成后再继续导航。
解决方案
1. 直接在provider.vue中等待Store数据初始化
当前代码中,只要user存在就立即触发跳转,但此时Store数据可能还未加载完成。修改provider.vue,确保等待数据加载完成后再执行导航:
const user = useSupabaseUser() const userStore = useUserStore() watch(user, async () => { if (user.value) { // 等待Store数据初始化完成 await userStore.fetchInitialData() // 确认company已赋值后再跳转 if (userStore.company) { await useSteps().handleNavigateToNextStep() } } }, { immediate: true })
2. 用路由守卫全局控制导航(推荐)
通过Nuxt路由守卫拦截页面跳转,确保用户登录状态下Store数据已加载完成:
在plugins/router.ts中添加:
export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.use((router) => { router.beforeEach(async (to, from) => { const user = useSupabaseUser() const userStore = useUserStore() // 仅在用户已登录、未加载Store数据、且当前不是provider页面时拦截 if (user.value && !userStore.company && to.name !== 'provider') { await userStore.fetchInitialData() } }) }) })
3. 为Store添加加载状态标记
在Store中新增加载状态,方便组件判断数据是否就绪,避免重复请求:
export const useUserStore = defineStore({ id: 'UserStore', state: () => ({ company: null as Tables<'company'> | null, isLoading: false }), actions: { async fetchInitialData() { // 避免重复加载 if (this.isLoading || this.company) return this.isLoading = true try { const [companyData] = await Promise.all([ useCompany().getCompany(), ]) this.company = companyData; } finally { this.isLoading = false } }, } })
在需要使用company的组件中,可通过加载状态等待数据就绪:
const userStore = useUserStore() const { company, isLoading } = storeToRefs(userStore) onMounted(async () => { if (!company.value && !isLoading.value) { await userStore.fetchInitialData() } })
4. 优化app.vue中的useAsyncData(若保留该方案)
如果坚持使用app.vue中的useAsyncData,需确保它能真正阻塞导航,并在user变化时正确触发:
const user = useSupabaseUser() const userStore = useUserStore() await useAsyncData('userStoreData', async () => { if (user.value) { await userStore.fetchInitialData() } }, { watch: [user], server: false // 仅在客户端执行,避免服务端渲染时的问题 })
同时修改provider.vue,监听company状态后再跳转:
const user = useSupabaseUser() const userStore = useUserStore() const { company } = storeToRefs(userStore) watch([user, company], async () => { if (user.value && company.value) { await useSteps().handleNavigateToNextStep() } }, { immediate: true })
内容的提问来源于stack exchange,提问作者Phillip
相关产品推荐
相关产品推荐

