Firebase onAuthStateChanged初始值为null致页面刷新后重定向问题
问题解决:刷新仪表盘页面被错误重定向到登录页
问题原因
页面刷新时Zustand的状态会被重置为初始值(username: null),而Firebase的onAuthStateChanged是异步执行的——在它完成用户状态校验并更新Zustand状态之前,路由已经根据初始的null值触发了重定向,导致明明处于登录状态却被踢回登录页。
解决方案
核心思路是在Firebase auth状态初始化完成前,不要执行路由判断,需要给状态添加一个加载标识,避免过早触发重定向逻辑。
步骤1:更新Zustand Store,添加加载状态
给store新增isAuthLoading字段,用来标记Firebase是否还在校验用户身份:
import { create } from 'zustand'; const useUserStore = create((set) => ({ username: null, isAuthLoading: true, // 初始为加载中状态 setUser: (user) => set({ username: user }), setAuthLoading: (loading) => set({ isAuthLoading: loading }), }));
步骤2:在App组件中处理加载状态
在onAuthStateChanged回调完成后更新加载状态;加载未完成时,显示加载提示而非直接渲染路由:
function App() { const setUserData = useUserStore((state) => state.setUser); const setAuthLoading = useUserStore((state) => state.setAuthLoading); const { userData, isAuthLoading } = useUserStore(state => ({ userData: state.username, isAuthLoading: state.isAuthLoading })); useEffect(() => { const unsubscribe = onAuthStateChanged(auth, (user) => { setUserData(user ? user.email : null); setAuthLoading(false); // 身份校验完成,关闭加载状态 }); return () => unsubscribe(); }, [setUserData, setAuthLoading]); // 加载中时显示占位内容 if (isAuthLoading) { return <div>加载中...</div>; } const router = createBrowserRouter([ { path: "/login", element: <Login /> }, { path: "/dashboard", element: userData ? <Dashboard /> : <Navigate to="/login" /> } ]); return <RouterProvider router={router} />; }
优化方案:使用路由守卫组件(推荐)
把权限校验逻辑封装成独立的ProtectedRoute组件,让路由结构更清晰:
// 新建ProtectedRoute组件 function ProtectedRoute({ children }) { const { userData, isAuthLoading } = useUserStore(state => ({ userData: state.username, isAuthLoading: state.isAuthLoading })); if (isAuthLoading) { return <div>加载中...</div>; } return userData ? children : <Navigate to="/login" />; }
然后修改路由定义:
const router = createBrowserRouter([ { path: "/login", element: <Login /> }, { path: "/dashboard", element: ( <ProtectedRoute> <Dashboard /> </ProtectedRoute> ) } ]);
调整Dashboard组件
现在可以简化Dashboard的逻辑,因为权限校验已经由ProtectedRoute完成:
function Dashboard() { const username = useUserStore(state => state.username); return <div>Hi, {username}</div>; }
内容的提问来源于stack exchange,提问作者vinDev
相关产品推荐
相关产品推荐

