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

Firebase Auth与React受保护路由持续重定向问题排查

问题:React + Firebase 受保护路由登录后仍重定向到登录页

我是React和Firebase新手,实现了登录页和需要保护的个人资料页,PrivateRoute的逻辑是:若用户已认证,将authorised设为true,允许访问个人资料页;否则重定向至登录页。但用户成功登录后,访问/profile仍被持续重定向到/sign-in,请问这是为什么?

受保护路由代码:

import { getAuth, onAuthStateChanged } from "firebase/auth";
import { Navigate, Outlet } from "react-router-dom";
import { useState, useEffect } from "react";

const PrivateRoute = () => {
    const auth = getAuth();
    const [authorised, setAuthorised] = useState(false);
    onAuthStateChanged(auth, (user) => {
        if (user) {
            setAuthorised(true);
        }
        if (!user) {
            setAuthorised(false);
        }
    });
    return(
        authorised ? <Outlet/> : <Navigate to="/sign-in"/>
    )
}

export default PrivateRoute;

App.js代码:

import { Route, Routes } from "react-router-dom";
import Profile from "./pages/Profile"

function App() {
  return (
    <div>
      <Route path="/sign-in" element={<SignIn />} />

      <Route element={<PrivateRoute />}> 
        <Route path="/profile" element={<Profile />} />
      </Route>
  );
}

问题原因及修复方案

1. 未用useEffect包裹监听逻辑

直接在组件函数内调用onAuthStateChanged会导致每次组件渲染都重新注册监听,且初始authorised为false,组件首次渲染时会直接触发重定向,后续状态更新可能因渲染时机问题失效。

修复方式:将监听逻辑放入useEffect,确保仅在组件挂载时注册一次,同时清理监听避免内存泄漏:

import { getAuth, onAuthStateChanged } from "firebase/auth";
import { Navigate, Outlet } from "react-router-dom";
import { useState, useEffect } from "react";

const PrivateRoute = () => {
    const auth = getAuth();
    const [authorised, setAuthorised] = useState(false);

    useEffect(() => {
        // 注册监听并保存取消订阅函数
        const unsubscribe = onAuthStateChanged(auth, (user) => {
            setAuthorised(!!user); // 简化判断,直接将user转为布尔值
        });
        // 组件卸载时取消监听
        return unsubscribe;
    }, [auth]);

    return authorised ? <Outlet/> : <Navigate to="/sign-in"/>
}

export default PrivateRoute;

2. 缺失加载状态导致过早重定向

初始authorised设为false时,Firebase验证用户状态需要时间,此时组件会直接重定向到登录页,即便后续验证通过也无法挽回。

新增loading状态,在验证完成前不执行重定向:

import { getAuth, onAuthStateChanged } from "firebase/auth";
import { Navigate, Outlet } from "react-router-dom";
import { useState, useEffect } from "react";

const PrivateRoute = () => {
    const auth = getAuth();
    const [authorised, setAuthorised] = useState(false);
    const [loading, setLoading] = useState(true); // 新增加载状态

    useEffect(() => {
        const unsubscribe = onAuthStateChanged(auth, (user) => {
            setAuthorised(!!user);
            setLoading(false); // 验证完成后结束加载
        });
        return unsubscribe;
    }, [auth]);

    // 加载中时返回提示,避免过早重定向
    if (loading) {
        return <div>加载中...</div>;
    }

    return authorised ? <Outlet/> : <Navigate to="/sign-in"/>
}

export default PrivateRoute;

3. App.js的路由结构错误

你的App.js缺少Routes包裹所有路由,且未导入SignIn组件,会导致路由无法正常工作:

import { Route, Routes } from "react-router-dom";
import Profile from "./pages/Profile";
import SignIn from "./pages/SignIn"; // 导入SignIn组件

function App() {
  return (
    <div>
      <Routes> {/* 必须用Routes包裹所有Route */}
        <Route path="/sign-in" element={<SignIn />} />
        <Route element={<PrivateRoute />}> 
          <Route path="/profile" element={<Profile />} />
        </Route>
      </Routes>
    </div>
  );
}

export default App;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 06:10:19