无需Context API/Redux,如何用Firebase Auth实现React受保护路由?
React + Firebase 实现路由保护(不使用Context/Redux)
问题背景
开发了一个简易React应用,用户可通过邮箱和密码使用Firebase登录。需求是:已登录用户能访问/profile路由,未登录用户无法访问。
当前代码(修改后仍无效)
import { useEffect, useState } from "react"; import { getAuth, onAuthStateChanged } from "firebase/auth"; import { Routes, Route, Navigate } from "react-router-dom"; function App() { const auth = getAuth(); const currUser = auth.currentUser; const ProtectedRoute = ({ user, children }) => { if (!currUser) { return <Navigate to="/" replace />; } return children; }; return ( <div> <Routes> <Route path="/" element={<HomePage />} /> <Route path="signin" element={<SignIn />} /> <Route path="signup" element={<Signup />} /> <Route path="/profile" element={ <ProtectedRoute user={currUser}> <Profile /> </ProtectedRoute> } /> <Route path="*" element={<p>There's nothing here: 404!</p>} /> </Routes> </div> ); } export default App;
问题原因
直接读取auth.currentUser会初始为null,因为Firebase需要异步验证用户登录状态。当访问/profile时,初始currUser为null,受保护路由会立即重定向到/;之后Firebase完成验证并更新currUser为实际用户,但此时重定向已经完成,无法回到/profile。
解决方案(不使用Context/Redux)
通过useState维护用户状态,结合onAuthStateChanged监听状态变化,同时处理加载状态避免过早重定向:
修改后的完整代码
import { useEffect, useState } from "react"; import { getAuth, onAuthStateChanged } from "firebase/auth"; import { Routes, Route, Navigate } from "react-router-dom"; function App() { // 初始设为undefined,区分「未加载完成」和「未登录」状态 const [currUser, setCurrUser] = useState(undefined); const auth = getAuth(); useEffect(() => { // 监听Firebase用户状态变化 const unsubscribe = onAuthStateChanged(auth, (user) => { setCurrUser(user); }); // 组件卸载时取消监听,避免内存泄漏 return unsubscribe; }, [auth]); // 未加载完成时,显示加载提示(可替换为自定义加载组件) if (currUser === undefined) { return <div>加载中...</div>; } const ProtectedRoute = ({ children }) => { // 确认未登录时才重定向 if (!currUser) { return <Navigate to="/" replace />; } return children; }; return ( <div> <Routes> <Route path="/" element={<HomePage />} /> <Route path="signin" element={<SignIn />} /> <Route path="signup" element={<Signup />} /> <Route path="/profile" element={ <ProtectedRoute> <Profile /> </ProtectedRoute> } /> <Route path="*" element={<p>There's nothing here: 404!</p>} /> </Routes> </div> ); } export default App;
方案说明
- 状态区分:用
undefined表示Firebase还在验证用户状态,null表示未登录,用户对象表示已登录 - 异步监听:
onAuthStateChanged会在Firebase完成用户验证后触发,自动更新currUser状态 - 加载处理:未加载完成时不渲染路由,避免初始
null导致的错误重定向 - 路由保护逻辑:只有确认用户未登录(
currUser为null)时,才重定向到首页;已登录则正常渲染目标页面
内容的提问来源于stack exchange,提问作者Aaryan
相关产品推荐
相关产品推荐

