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
相关产品推荐
相关产品推荐

