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

React Router RouterProvider中Firebase onAuthStateChange实现刷新保登录

解决React Router RouterProvider下Firebase Auth状态刷新丢失问题

核心问题原因

刷新页面时,authProvider.user初始为null,而Firebase的认证状态需要异步从本地存储恢复,此时loader已执行并返回null,导致页面获取不到有效用户信息。之前在React上下文中用useEffect监听onAuthStateChanged的方式,需要调整为应用启动时就在React树外初始化监听,同时让loader等待认证状态恢复完成。

解决方案代码修改

1. 更新authProvider,添加初始化监听与等待方法

import { getAuth, signInWithEmailAndPassword, signOut, onAuthStateChanged, User } from "firebase/auth";

const auth = getAuth();

interface AuthProvider {
  user: User | null;
  login(email: string, password: string): Promise<any>;
  signout(): Promise<void>;
  waitForInitialUser(): Promise<User | null>;
}

export const authProvider: AuthProvider = {
  user: null,
  // 用于等待初始用户状态加载完成的Promise
  _initialUserPromise: null as Promise<User | null> | null,

  async login(email: string, password: string) {
    try {
      const userCredential = await signInWithEmailAndPassword(auth, email, password);
      authProvider.user = userCredential.user;
      return redirect("/dashboard");
    } catch {
      toast.error("邮箱或密码无效");
    }
  },

  async signout() {
    await signOut(auth);
    authProvider.user = null;
  },

  // 初始化认证状态监听
  init() {
    if (!this._initialUserPromise) {
      this._initialUserPromise = new Promise((resolve) => {
        const unsubscribe = onAuthStateChanged(auth, (user) => {
          authProvider.user = user;
          resolve(user);
          // 若需要实时同步用户状态变化(如异地登出),可移除unsubscribe()
          unsubscribe();
        });
      });
    }
  },

  // 供loader调用,等待初始用户状态加载完成
  async waitForInitialUser() {
    if (!this._initialUserPromise) {
      this.init();
    }
    return this._initialUserPromise;
  },
};

2. 在应用入口初始化authProvider

在React应用入口文件(如main.tsx)中,启动时调用初始化方法:

import { authProvider } from "./path-to-auth-provider";

// 提前初始化认证状态监听
authProvider.init();

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

3. 修改loader,等待用户状态初始化

在仪表板的loader中,先等待认证状态恢复,再返回用户信息:

import { authProvider } from "./path-to-auth-provider";

export async function loader() {
  const user = await authProvider.waitForInitialUser();
  // 用户未登录则重定向到登录页
  if (!user) {
    return redirect("/login");
  }
  return { user };
}

关键说明

  • onAuthStateChanged在应用启动时触发,会自动从本地存储恢复用户登录状态,同步更新authProvider.user。
  • waitForInitialUser()确保loader不会在用户状态未就绪时返回null,保证刷新页面时能拿到有效用户数据。
  • 若需要实时监听用户状态变化(如其他设备登出、用户信息更新),可移除unsubscribe(),保持监听持续生效。

内容的提问来源于stack exchange,提问作者Abdulbasit Yusuf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 23:19:55