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

React+react-router+Firebase项目刷新页面跳转登录页问题解决

问题根因

  1. 初始状态时序问题:Redux 中 currentUser 初始值为 null,页面刷新后 Firebase 身份校验是异步执行的,在 auth 状态返回前,权限校验钩子就已经触发,识别到 currentUser 为空直接跳转登录页。
  2. 用户数据覆盖bug:App.js 中 auth 监听逻辑错误,你在已登录分支设置完带 Firestore 扩展字段(如 roles)的用户信息后,外部还执行了一次 setCurrentUser(userAuth),会把带 roles 的完整用户对象覆盖为 Firebase 原生的 auth 对象,原生对象没有存储在 Firestore 里的 roles 字段,导致管理员身份校验永远失败,刷新后停留在登录页。

修复步骤

1. 修复App.js的auth监听逻辑

把全局的 setCurrentUser(userAuth) 移到未登录的 else 分支,避免覆盖带扩展字段的用户信息:

useEffect(() => {
  const authListener = auth.onAuthStateChanged(async (userAuth) => {
    if (userAuth) {
      const userRef = await handleUserProfile(userAuth);
      userRef.onSnapshot((snapshot) => {
        setCurrentUser({
          id: snapshot.id,
          ...snapshot.data(),
        });
      });
    } else {
      // 仅未登录时设置用户为null
      setCurrentUser(userAuth);
    }
  });
  return () => {
    authListener();
  };
}, []);

2. 新增auth加载状态,避免未完成校验时触发跳转

修改userReducer,新增加载状态标记:

const INITIAL_STATE = {
  currentUser: null,
  authLoading: true, // 标记身份校验是否完成
};
const userReducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case userTypes.SET_CURRENT_USER:
      return {
        ...state,
        currentUser: action.payload,
        authLoading: false, // 身份校验完成,关闭加载态
      };
    default:
      return state;
  }
};

3. 修改权限校验钩子,加载状态下不执行跳转

修改useAuth:

const mapState = ({ user }) => ({
  currentUser: user.currentUser,
  authLoading: user.authLoading,
});
const useAuth = (props) => {
  const { currentUser, authLoading } = useSelector(mapState);
  useEffect(() => {
    if (authLoading) return; // 校验中不跳转
    if (!currentUser) {
      props.history.push("/login");
    }
  }, [currentUser, authLoading]);
  return !authLoading && currentUser;
};

修改useAdmin:

const mapState = ({ user }) => ({
  currentUser: user.currentUser,
  authLoading: user.authLoading,
});
const useAdmin = (props) => {
  const { currentUser, authLoading } = useSelector(mapState);
  const history = useHistory();
  useEffect(() => {
    if (authLoading) return; // 校验中不跳转
    if (!checkUserAdmin(currentUser)) {
      history.push("/login");
    }
  }, [currentUser, authLoading]);
  return !authLoading && checkUserAdmin(currentUser);
};

4. 可选优化:增加全局加载态避免页面闪烁

修改App.js的mapStateToProps引入加载状态,校验完成前渲染加载占位符:

const mapStateToProps = ({ user }) => ({
  currentUser: user.currentUser,
  authLoading: user.authLoading,
});

const App = (props) => {
  const { setCurrentUser, currentUser, authLoading } = props;
  // 校验未完成时显示加载
  if (authLoading) return <div>加载中...</div>
  // 原有return逻辑不变
  ...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 12:45:05