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

React Firebase认证项目useContext刷新瞬时为null导致私有路由访问异常

问题根因

  1. AuthContext.js 中的useEffect配置存在错误
    • 依赖项错误添加了user,会导致每次user值变化时都重新注册身份状态监听器,造成重复执行
    • 清理函数直接调用了unsub(),会导致监听器注册完成后立刻被销毁,后续身份状态变化无法被正常监听
  2. 缺少身份校验等待状态:Firebase的onAuthStateChanged是异步回调,页面刷新后初始user为null,在Firebase返回用户身份信息前的空窗期,AuthGuard会直接判定为未登录,触发跳转到登录页的逻辑

修复方案

1. 修改AuthContext.js

  • 新增loading状态记录身份校验进度,初始值为true
  • 修正useEffect的依赖项为空数组,仅在组件挂载时注册一次监听器
  • 修正清理函数写法,仅在组件卸载时销毁监听器
  • 身份校验完成后同步更新user和loading状态,将loading暴露到context中
import React, { useContext, useEffect, useState } from "react";
import { firebaseAuth } from "../firebase";
import {
  createUserWithEmailAndPassword,
  signOut,
  signInWithEmailAndPassword,
  onAuthStateChanged,
} from "firebase/auth";

const AuthContext = React.createContext();

export const useAuth = () => {
  return useContext(AuthContext);
};

export const AuthContextProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  // 新增loading状态
  const [loading, setLoading] = useState(true);

  console.log("Auth Context User:", user);

  useEffect(() => {
    const unsub = onAuthStateChanged(firebaseAuth, (user) => {
      setUser(user);
      // 身份校验完成,关闭loading
      setLoading(false);
    });
    // 修正清理函数,仅在组件卸载时调用unsub
    return unsub;
  // 依赖项改为空数组,仅挂载执行一次
  }, []);

  function SignUp(email, password) {
    return createUserWithEmailAndPassword(firebaseAuth, email, password);
  }

  function Logout() {
    return signOut(firebaseAuth);
  }

  function Login(email, password) {
    return signInWithEmailAndPassword(firebaseAuth, email, password);
  }

  const value = {
    logout: Logout,
    signup: SignUp,
    login: Login,
    user,
    // 暴露loading到context
    loading
  };

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};

2. 修改AuthGuard.js

  • 新增loading判断,身份校验完成前渲染加载占位内容,不触发跳转逻辑
import React from "react";
import { Navigate, useLocation } from "react-router-dom";
import { useAuth } from "../context/AuthContext";

const AuthGuard = ({ children }) => {
  let { user, loading } = useAuth();
  let location = useLocation();

  console.log("user", user);

  // 校验中返回加载状态,避免误跳转
  if(loading) {
    // 可替换为自定义加载动画组件
    return <div>加载中...</div>
  }

  if (!user) {
    return <Navigate to="/" state={{ from: location }} />;
  }

  return children;
};

export default AuthGuard;

内容的提问来源于stack exchange,提问作者Tirth Trivedi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 04:36:07