You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 09:20:42