首页 > 解决方案 > React Router 在通过导航重定向后不会加载新的页面组件

问题描述

我是 React Hooks 的新手并尝试使用它们 + 实验性 React Router 版本 6 库,因此我不必在将来的某个时候将我的代码从版本 5 升级到 6

注意:第 6 版与第 5 版不兼容,因此“否Switch”不是答案;)

想法:创建一个简单的管理应用程序,您可以通过单击按钮登录/注销。管理页面受到访问锁的保护,因此没有人可以通过直接 URL 访问它。

问题:单击登录按钮后,URL 更改为/admin,但我看不到管理页面(仅在页面刷新或通过 强制页面刷新后windows.location.reload())。

这是 React Router v6 中的问题还是我以错误的方式使用 API?源代码(https://codesandbox.io/s/quirky-black-rsdy0):

import React, {useEffect, useState} from "react";
import {BrowserRouter, Route, Routes, useNavigate} from "react-router-dom";

async function isLoggedIn() {
    // In real life this function is calling a REST endpoint and awaiting the result
    return localStorage.getItem("loggedin") !== null;
}

async function setLoginStatus(status) {
    // In real life this function is calling a REST endpoint and awaiting the result
    if (status === true) {
        localStorage.setItem("loggedin", true);
    } else {
        localStorage.removeItem("loggedin");
    }
}

function LoginPage() {
    const navigate = useNavigate();

    async function handleLogin(event) {
        event.preventDefault();
        await setLoginStatus(true);
        navigate("/admin"); // --> The user is logged in and the URL changes to /admin, but he doesn't see the admin page (Only after a page refresh)
        //window.location.reload(); // Hack to reload the page to see the admin page
    }

    return (
        <form onSubmit={handleLogin}>
            <button type="submit">Login</button>
        </form>
    );
}

function LogoutPage() {
    const navigate = useNavigate();

    useEffect(() => {
        const logoutAccount = async () => {
            await setLoginStatus(false);
            navigate("/login");
        };
        logoutAccount();
    });

    return <p>Logging out</p>;
}

function AdminPage() {
    return (
        <div>
            <p>The secured admin page</p>
            <a href="/logout">Logout</a>
        </div>
    );
}

function AuthenticationLock(props) {
    if (props.isLoggedIn === true) {
        return <div>{props.children}</div>;
    } else {
        return <LoginPage/>;
    }
}

export default function App() {

    const [loginStatus, setAppLoginStatus] = useState(false);

    useEffect(() => {
        const login = async () => {
            const value = await isLoggedIn();
            setAppLoginStatus(value);
        };
        login();
    });

    return (
        <BrowserRouter>
            <AuthenticationLock isLoggedIn={loginStatus}>
                <Routes>
                    <Route path="/" element={<AdminPage/>}/>
                    <Route path="/admin" element={<AdminPage/>}/>
                    <Route path="/login" element={<LoginPage/>}/>
                    <Route path="/logout" element={<LogoutPage/>}/>
                    <Route path="/*" element={<AdminPage/>}/>
                </Routes>
            </AuthenticationLock>
        </BrowserRouter>
    );
}

标签: javascriptreactjsreact-routerreact-router-dom

解决方案


不知何故,我AuthenticationLock对这个问题负责。我改变了一个不同的设计,现在它可以工作了:

import React, { useEffect } from "react";
import {
  BrowserRouter,
  Route,
  Routes,
  Link,
  useNavigate
} from "react-router-dom";

function isLoggedIn() {
  // In real life this function is calling a REST endpoint and awaiting the result
  return localStorage.getItem("loggedin") !== null;
}

async function setLoginStatus(status) {
  // In real life this function is calling a REST endpoint and awaiting the result
  if (status) {
    localStorage.setItem("loggedin", "1");
  } else {
    localStorage.removeItem("loggedin");
  }
}

function DashboardPage() {
  return (
    <div>
      <h1>Dashboard page</h1>
      <p>This is the dashboard page</p>
      <Link to={"/accounts"}>Accounts</Link>
      <br />
      <Link to={"/logout"}>Logout</Link>
    </div>
  );
}

function AccountsPage() {
  return (
    <div>
      <h1>Accounts page</h1>
      <p>This is the accounts page</p>
      <Link to={"/dashboard"}>Dashboard</Link>
      <br />
      <Link to={"/logout"}>Logout</Link>
    </div>
  );
}

function LoginPage() {
  const navigate = useNavigate();

  async function handleLogin(event) {
    event.preventDefault();
    await setLoginStatus(true);
    navigate("/dashboard");
  }

  return (
    <div>
      <h1>Login</h1>
      <form onSubmit={handleLogin}>
        <button type="submit">Login</button>
      </form>
    </div>
  );
}

function LogoutPage() {
  const navigate = useNavigate();

  useEffect(() => {
    const logoutAccount = async () => {
      await setLoginStatus(false);
      navigate("/login");
    };
    logoutAccount();
  });

  return <p>Logging out</p>;
}

const PrivateRoute = ({ component, ...rest }) => {
  if (isLoggedIn()) {
    const routeComponent = props => React.createElement(component, props);
    return <Route {...rest} render={routeComponent} />;
  } else {
    return <LoginPage />;
  }
};

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <PrivateRoute path="/" element={<DashboardPage />} />
        <PrivateRoute path="/dashboard" element={<DashboardPage />} />
        <PrivateRoute path="/accounts" element={<AccountsPage />} />
        <Route path="/login" element={<LoginPage />} />
        <PrivateRoute path="/logout" element={<LogoutPage />} />
        <PrivateRoute path="/*" element={<DashboardPage />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

推荐阅读