React-Router-Dom 改变页面状态

React-Router-Dom changing states of the page

大家好,我有一个问题。当我输入私人路线“仪表板”时,它会将我重定向到“登录”,然后再转到仪表板。 True 和 False 一起玩。我怎样才能修复它而不是将我重定向到登录然后到仪表板。

视频示例: https://cdn.aboutluc.xyz/images/rc64kb6af92sswn3r4mv.mp4

代码:

import React, {
  useState,
  useEffect
} from "react"

import { toast } from "react-toastify"

import {
  BrowserRouter as Router,
  Routes,
  Route,
  Navigate
} from "react-router-dom"

import {
  Login,
  Register,
  Dashboard,
} from "./Pages"

import {
  Navbar
} from "./Components"

import './App.css'
import "react-toastify/dist/ReactToastify.css"
import 'bootstrap/dist/css/bootstrap.min.css'

toast.configure()

const App = () => {

  const [ isAuthenticated, setIsAuthenticated ] = useState()

  const setAuth = (boolean) => {
    setIsAuthenticated(boolean)
  }

  const isAuth = async () => {
    try {
      const res = await fetch("http://localhost:5000/api/auth/verify", {
        headers: { JwtToken: localStorage.JwtToken }
      });

      const parseRes = await res.json();

      parseRes === true ? setIsAuthenticated(true) : setIsAuthenticated(false);
    } catch (error) {
      console.error(error)
    }
  }

  useEffect(() => {
    isAuth()
  }, [])

  return (
    <>
      <Router>
        <Navbar setAuth={setAuth} isAuthenticated={isAuthenticated} />
        <Routes>

          <Route
            exact
            path="/login"
            element={
              isAuthenticated ? (
                <Navigate replace={true} to="/dashboard" />
              ) : (
                <Login setAuth={setAuth} />
              )
            }
          />

          <Route
            exact
            path="/register"
            element={
              isAuthenticated ? (
                <Navigate replace={true} to="/dashboard" />
              ) : (
                <Register setAuth={setAuth} />
              )
            }
          />

          <Route
            exact
            path="/dashboard"
            element={
              isAuthenticated ? (
                
                <Dashboard setAuth={setAuth} />
              ) : (
                <Navigate replace={true} to="/login" />
              )
            }
          />

        </Routes>
      </Router>
    </>
  )
}

export default App

我看到的可能问题是初始渲染中的“间隙”,其中 isAuthenticated 状态未定义,而设置该状态的 useEffect 挂钩回调尚未 运行然而。如果您尝试直接访问受保护的路由,那么无论 实际 身份验证状态如何,代码都会将您跳转到登录路由。

为此,您通常希望使用“第三”不确定状态来“保持”重定向到身份验证或允许访问受保护的组件,直到身份验证状态得到确认。

将身份验证状态抽象为身份验证布局组件。

const AuthLayout = ({ isAuthenticated }) => {
  if (isAuthenticated === undefined) return null; // or loading spinner, etc...

  return isAuthenticated
    ? <Outlet />
    : <Navigate to="/login" replace />;
};

const AnonymousLayout = ({ isAuthenticated, to }) => {
  if (isAuthenticated === undefined) return null; // or loading spinner, etc...

  return isAuthenticated
    ? <Navigate to={to} replace />
    : <Outlet />;
};

将布局用于 guard/protect 特定路线。

<Routes>
  <Route
    element={(
      <AnonymousLayout isAuthenticated={isAuthenticated} to="/dashboard" />
    )}
  >
    <Route path="/login" element={<Login setAuth={setAuth} />} />
    <Route path="/register" element={<Register setAuth={setAuth} />} />
  </Route>
  <Route element={<AuthLayout isAuthenticated={isAuthenticated} />}>
    <Route path="/dashboard" element={<Dashboard setAuth={setAuth} />} />
  </Route>
</Routes>

注意:您只能在安装 App 组件时调用 isAuth。您可能希望调用此函数或以其他方式比这更频繁地验证您的身份验证令牌。将 isAuth 传递到路由包装器并在 useEffect 挂钩中调用可能不是一个糟糕的主意。