Nuxt4+BetterAuth导航栏无法动态更新,仅刷新后生效求助
问题:Nuxt4 + BetterAuth 导航栏session状态无法实时更新
我用Nuxt4搭配BetterAuth和Supabase开发,默认布局里的导航栏组件无法动态更新session状态,只有手动刷新页面(F5)后才会显示正确状态。
项目目录结构
app/ ├─ components/ │ ├─ AddTask.vue │ ├─ LoginUser.vue │ ├─ RegisterUser.vue │ └─ TheNavbar.vue ├─ composables/ │ └─ useAuth.ts ├─ layouts/ │ └─ default.vue ├─ middleware/ │ └─ auth.global.ts ├─ pages/ ├─ schemas/ ├─ ui/ ├─ utils/ ├─ app.vue ├─ better-auth_migrations/ ├─ node_modules/ ├─ public/ ├─ server/ └─ .env
相关代码
useAuth.ts
import { authClient } from "../utils/auth-client"; import { useFetch } from "#app"; import { ref } from "vue"; export const useAuth = () => { const session = ref(null); const init = async () => { const { data } = await authClient.useSession(useFetch); session.value = data.value; }; init(); const logout = async () => { await authClient.signOut(); session.value = null; return navigateTo("/login"); }; return { session, logout }; };
TheNavbar.vue
<script lang="ts" setup> import { useAuth } from "../composables/useAuth"; const { session, logout } = useAuth(); import BaseButton from "~/ui/BaseButton.vue"; </script> <template> <nav class="bg-gray-800 p-4 text-white"> <div class="container mx-auto flex justify-between items-center"> <div class="text-lg font-semibold"> <NuxtLink to="/" class="mr-4 hover:underline">MAIN</NuxtLink> </div> <div> <NuxtLink to="/login" class="mr-4 hover:underline">LOGIN</NuxtLink> <NuxtLink to="/register" class="mr-4 hover:underline" >REGISTER</NuxtLink > <NuxtLink to="/add" class="mr-4 hover:underline">ADD</NuxtLink> <NuxtLink to="/view" class="hover:underline">VIEW TASKS</NuxtLink> <BaseButton @click="logout" color="blue" label="LOGOUT" type="button" /> </div> </div> <p>{{ session }}</p> </nav> </template>
解决思路
1. 监听BetterAuth的session变化事件
BetterAuth客户端提供了session变更的监听机制,在useAuth中订阅session的实时更新,替代仅初始化时获取一次的逻辑:
修改useAuth.ts:
import { authClient } from "../utils/auth-client"; import { useFetch } from "#app"; import { ref, onMounted, onUnmounted } from "vue"; export const useAuth = () => { const session = ref(null); const init = async () => { const { data } = await authClient.useSession(useFetch); session.value = data.value; }; let unsubscribe: (() => void) | undefined; onMounted(async () => { await init(); // 订阅session更新,自动同步状态 unsubscribe = authClient.onSessionChange((newSession) => { session.value = newSession; }); }); onUnmounted(() => { unsubscribe?.(); }); const logout = async () => { await authClient.signOut(); return navigateTo("/login"); }; return { session, logout }; };
2. 改用Nuxt全局共享状态
组件级ref无法跨组件共享状态,多次调用useAuth会创建独立的session实例。改用Nuxt的useState实现全局状态共享:
修改useAuth.ts:
import { authClient } from "../utils/auth-client"; import { useFetch, useState } from "#app"; import { onMounted, onUnmounted } from "vue"; export const useAuth = () => { // 创建全局共享的session状态 const session = useState("auth-session", () => null); const init = async () => { const { data } = await authClient.useSession(useFetch); session.value = data.value; }; let unsubscribe: (() => void) | undefined; onMounted(async () => { await init(); unsubscribe = authClient.onSessionChange((newSession) => { session.value = newSession; }); }); onUnmounted(() => { unsubscribe?.(); }); const logout = async () => { await authClient.signOut(); return navigateTo("/login"); }; return { session, logout }; };
3. 同步响应式数据引用
如果BetterAuth的useSession返回的data本身是响应式对象,可直接让session ref指向该响应式数据,替代单次赋值:
修改useAuth.ts中的init函数:
import { toRef } from "vue"; // ... const init = async () => { const { data } = await authClient.useSession(useFetch); // 同步响应式数据引用,确保状态实时更新 session.value = toRef(data, 'value').value; };
4. 检查全局中间件逻辑
查看auth.global.ts中间件,确保它没有维护独立状态,而是通过调用useAuth来同步最新的session状态,避免路由跳转时状态不同步。
内容的提问来源于stack exchange,提问作者Kacper
相关产品推荐
相关产品推荐

