reactjs 如何为React应用创建仅限登录的路由?

vltsax25  于 5个月前  发布在  React
关注(0)|答案(2)|浏览(66)

我试图创建一个MERN堆栈Facebook克隆,如果用户没有登录,他们将被带到一个带有注册/登录表单的着陆页。如果用户登录,他们将被带到主应用程序"/""/messages""/profile""/users/:userID"路由。
最初我把它们都放在app.js中,用一个isLoggedIn函数返回一个布尔值。我试着做了下面的事情,但是现在它找不到我的任何登录路由,除了"/"。在"/""/welcome"上一切正常,在app.js中重定向是双向的。
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, { useState } from 'react';
import Feed from '../feed/Feed';
import HomePage from '../../pages/HomePage';
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>
      {/* ====== AUTHENTICATION ONLY - Search, Messages, Friends, Notifications : ======== */}
      <Route
        path='/'
        element={isLoggedIn()
          ? <AuthenticatedRoutes navigate={navigate} />
          : <Navigate to='/welcome' />
        }
      />

      {/* ====== NO AUTHENTICATION - Sign Up or Login: ======== */}
      <Route
        path='/welcome'
        element={!isLoggedIn()
          ? <LandingPage navigate={navigate} />
          : <Navigate to='/' />
        }
      />
    </Routes>
  );
}

export default App;


AuthenticatedRoutes.js -我对每个经过身份验证的页面使用相同的布局,所以跳到路由部分的“MAIN DIV”。

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 HomePage from '../../pages/HomePage';
import ProfilePage from '../../pages/ProfilePage';
import OwnProfilePage from '../../pages/OwnProfilePage';
import MessengerPage from '../../pages/MessengerPage';
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);

  // ===== LOGIN POPUP & TIMEOUT CHECKER: COPY TO EVERY AUTHENTICATED PAGE: ==========   
  const showLoginPopup = !useSessionTimeOutCheck(); // checks every 5 seconds if token is valid and changes true/false

  // on component mount: get sessionUserInfo 
  // TODO test:copy to every page, so that it reloads on every new page visit?
  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);
      })
    }
  },[])
  
  // =========== JSX FOR COMPONENT =================================== 
  return (
    <div className='h-screen w-screen bg-#bgGrey dark:bg-gray-900 flex flex-col'>

      {/* LOGGED OUT POPUP */}
      {showLoginPopup && 
        <div className='z-40 absolute h-full w-full'>
          <LoginPopup navigate={navigate} />
        </div>
        }

      {/* NAV BAR */}
      <div className='z-30'>
        <Navbar navigate={navigate} token={token} setToken={setToken} 
          sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>
      </div>

    {/* MAIN PAGE */}
    <div className='w-screen h-screen flex flex-row '>
    
      {/* MAIN DIV */}
      <div className='w-full h-full'>
        <Routes>
          {/* ------ FEED ------  */}
          <Route path='/'  element={
            <Feed navigate={navigate} token={token} setToken={setToken} 
          sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>} />
          
          {/* ------  PROFILE PAGE ------  */}
          <Route path="/users/:userID/"  element={ 
            <Profile navigate={navigate} token={token} setToken={setToken} 
          sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>}/>
          {/* ------  SESSION USER'S PROFILE PAGE ------  */}
          <Route path='/profile'  element={ 
            <OwnProfile navigate={navigate} token={token} setToken={setToken} 
          sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>}/>

          {/* ------  MESSAGES ------  */}
          {/* <Route path='/messages'  element={ 
            <MessengerPage navigate={navigate} token={token} setToken={setToken} 
            sessionUserID={sessionUserID} sessionUser={sessionUser} setSessionUser={sessionUser}/>}/> */}
        </Routes>
      </div>

      {/* MESSENGER DIV - Online friends */}
      <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;

gpfsuwkq

gpfsuwkq1#

呈现的路由AuthenticatedRoutes应该指定一个匹配器,这样所有的后代路由也可以被匹配和呈现,例如path="/*"。这应该允许AuthenticatedRoutes呈现的Routes组件匹配子路由。
有关详细信息,请参见Splats。

const App = () => {
  const navigate = useNavigate();

  return (
    <Routes>

      {/* ====== AUTHENTICATION ONLY - Search, Messages, Friends, Notifications : ======== */}
      <Route
        path='/*' // <-- allow sub-route matching
        element={isLoggedIn()
          ? <AuthenticatedRoutes navigate={navigate} />
          : <Navigate to='/welcome' replace />
        }
      />

      {/* ====== NO AUTHENTICATION - Sign Up or Login: ======== */}
      <Route
        path='/welcome'
        element={!isLoggedIn()
          ? <LandingPage navigate={navigate} />
          : <Navigate to='/' replace />
        }
      />

    </Routes>
  );
}

字符串
关于更传统的路由保护实现,请参阅我的答案here。基本要点是AuthenticatedRoutes将为嵌套路由呈现Outlet,而不是直接呈现后代路由。它导致代码更清晰,关注点分离。

llew8vvj

llew8vvj2#

要解决此问题,请在App.js和AuthenticatedRoutes.js中进行更改,以正确处理路由和身份验证。
在App.js中:

import React from 'react';
import { Routes, Route, Navigate } from "react-router-dom";
import LandingPage from '../../pages/LandingPage';
import AuthenticatedRoutes from './AuthenticatedRoutes';
import { isLoggedIn } from '../../utilities/LoggedInCheck';

const App = () => {
  return (
    <Routes>
    
    // Here the <AuthenticatedRoutes /> only rendered if the user is logged in, otherwise, it will redirects to the landing page.
      <Route
        path="/"
        element={isLoggedIn() ? <AuthenticatedRoutes /> : <LandingPage />}
      />
      <Route path="/welcome" element={<LandingPage />} />
    </Routes>
  );
};

export default App;

字符串
在AuthenticatedRoutes.js中:

import React, { useEffect, useState } from 'react';
import { Routes, Route } from "react-router-dom";
import { isLoggedIn } from '../../utilities/LoggedInCheck';
import LandingPage from '../../pages/LandingPage'; 
import Feed from '../feed/Feed';
import Profile from '../profilepage/Profile'; 
import OwnProfile from '../profilepage/OwnProfile';

const AuthenticatedRoutes = () => {
  const [isLoggedInState, setIsLoggedIn] = useState(isLoggedIn());

  useEffect(() => {
    setIsLoggedIn(isLoggedIn());
  }, []);

  if (!isLoggedInState) {
    return <LandingPage />;
  }

  return (
    <Routes>
      <Route path="/" element={<Feed />} />
      <Route path="/profile" element={<OwnProfile />} />
      <Route path="/users/:userID" element={<Profile />} />
      {/* other routes....*/}
    </Routes>
  );
};

export default AuthenticatedRoutes;

相关问题