如何为React应用配置仅登录可访问路由?MERN栈开发问题
MERN栈Facebook克隆项目路由重构问题
问题背景
- 项目需求:未登录用户自动跳转至包含注册/登录表单的
/welcome页面;登录用户可访问/、/messages、/profile和/users/:userID路由 - 重构前:所有路由集中在
App.js中,通过返回布尔值的isLoggedIn()函数控制权限,功能正常 - 重构后:仅
/和/welcome路由正常工作,登录状态下的其他路由(如/profile、/users/:userID)无法被识别
相关代码
Index.js
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './components/app/App'; import { BrowserRouter } from 'react-router-dom'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <BrowserRouter> <React.StrictMode> <App /> </React.StrictMode> </BrowserRouter> );
App.js
import './App.css'; import React from 'react'; import { useNavigate, Routes, Route, Navigate, } from "react-router-dom"; import { isLoggedIn } from '../../utilities/LoggedInCheck'; import LandingPage from '../../pages/LandingPage'; import AuthenticatedRoutes from './AuthenticatedRoutes'; const App = () => { const navigate = useNavigate(); return ( <Routes> {/* ====== 仅登录可访问路由 ======== */} <Route path='/' element={isLoggedIn() ? <AuthenticatedRoutes navigate={navigate} /> : <Navigate to='/welcome' /> } /> {/* ====== 未登录可访问路由 ======== */} <Route path='/welcome' element={!isLoggedIn() ? <LandingPage navigate={navigate} /> : <Navigate to='/' /> } /> </Routes> ); } export default App;
AuthenticatedRoutes.js
import React, { useState, useEffect } from 'react'; import { Routes, Route } from "react-router-dom"; import { useSessionTimeOutCheck } from '../../utilities/LoggedInCheck'; import { isLoggedIn } from '../../utilities/LoggedInCheck'; import LoginPopup from '../auth/LoginPopup'; import { findUser } from '../../api_calls/usersAPI'; import Profile from '../profilepage/Profile'; import OwnProfile from '../profilepage/OwnProfile'; import Navbar from '../navbar/Navbar'; import getSessionUserID from '../../utilities/GetSessionUserID'; import Feed from '../feed/Feed'; const AuthenticatedRoutes = ({ navigate }) => { const [token, setToken] = useState(window.localStorage.getItem('token')); const sessionUserID = getSessionUserID(token); const [sessionUser, setSessionUser] = useState(null); const showLoginPopup = !useSessionTimeOutCheck(); useEffect(() => { if (token && sessionUserID) { findUser(token, sessionUserID) .then(userData => { window.localStorage.setItem("token", userData.token) setToken(window.localStorage.getItem("token")) setSessionUser(userData.user); console.log(userData.user); }) } },[]) return ( <div className='h-screen w-screen bg-#bgGrey dark:bg-gray-900 flex flex-col'> {/* 登录超时弹窗 */} {showLoginPopup && <div className='z-40 absolute h-full w-full'> <LoginPopup navigate={navigate} /> </div> } {/* 导航栏 */} <div className='z-30'> <Navbar navigate={navigate} token={token} setToken={setToken} sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/> </div> {/* 主页面区域 */} <div className='w-screen h-screen flex flex-row '> {/* 主内容区 */} <div className='w-full h-full'> <Routes> {/* 首页信息流 */} <Route path='/' element={ <Feed navigate={navigate} token={token} setToken={setToken} sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>} /> {/* 其他用户主页 */} <Route path="/users/:userID/" element={ <Profile navigate={navigate} token={token} setToken={setToken} sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>}/> {/* 当前登录用户主页 */} <Route path='/profile' element={ <OwnProfile navigate={navigate} token={token} setToken={setToken} sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>}/> {/* 消息页面(注释状态) */} {/* <Route path='/messages' element={ <MessengerPage navigate={navigate} token={token} setToken={setToken} sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>}/> */} </Routes> </div> {/* 侧边栏在线好友区 */} <div className='flex flex-row items-center justify-between h-full sm:w-[28rem] md:w-[30.5rem] lg:w-[34.5rem] px-4 border-l-2'> MESSENGER </div> </div> </div> ); } export default AuthenticatedRoutes;
问题原因及解决方案
核心问题
App.js中仅将AuthenticatedRoutes挂载在/路径下,当访问/profile这类子路径时,App.js的Routes无法匹配到对应的路由规则,导致这些路径被忽略。同时,AuthenticatedRoutes内部的子路由使用了绝对路径,不符合嵌套路由的匹配逻辑。
修复步骤
修改App.js中的父路由规则
将父路由的path改为/*,确保所有以/开头的路径都能进入AuthenticatedRoutes进行匹配:<Route path='/*' element={isLoggedIn() ? <AuthenticatedRoutes navigate={navigate} /> : <Navigate to='/welcome' />} />调整AuthenticatedRoutes中的子路由为相对路径
去掉子路由路径开头的/,让路由基于父路径进行匹配:<Routes> {/* 首页信息流:使用index匹配父路径默认内容 */} <Route index element={ <Feed navigate={navigate} token={token} setToken={setToken} sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>} /> {/* 其他用户主页 */} <Route path="users/:userID" element={ <Profile navigate={navigate} token={token} setToken={setToken} sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>}/> {/* 当前登录用户主页 */} <Route path="profile" element={ <OwnProfile navigate={navigate} token={token} setToken={setToken} sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>}/> {/* 消息页面 */} <Route path="messages" element={ <MessengerPage navigate={navigate} token={token} setToken={setToken} sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>}/> </Routes>
补充说明
使用index路由替代原有的path='/',可以更清晰地表示这是父路由的默认内容。相对路径的嵌套路由会自动继承父路由的路径前缀,确保路由匹配逻辑正确。
内容的提问来源于stack exchange,提问作者Claire
相关产品推荐
相关产品推荐

