React Router通过navigate重定向后,不加载新的页面组件。

问题描述 投票:0回答:1

我是React Hooks的新手,尝试着玩了玩它们+实验性的React Router 6版本库,这样我就不用在未来的某一天把我的代码从5版本升级到6版本了。

注意:第6版与第5版不能兼容,所以没有。Switch 不是答案;)

想法: 创建一个简单的管理应用程序,你可以通过按钮点击登录退出。管理页面通过访问锁保护,所以没有人可以通过直接的URL访问它。

遇到的问题: 点击登录按钮后,URL改为 /admin但我没有看到管理页面(只有在页面刷新或通过强制刷新页面后才会看到 windows.location.reload()).

这是React Router v6中的问题还是我用错了API?源代码 (https:/codesandbox.iosquirky-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>
    );
}
javascript reactjs react-router react-router-dom
1个回答
1
投票

把你所有的路由都包起来 <Switch></Switch> 并设置道具 exact={true} 除了最后一条之外,所有的路线都是如此。

import {BrowserRouter, Route, Routes, Switch, useNavigate} from "react-router-dom";

[...]

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

0
投票

所以在这种情况下,我们需要在所有路由上使用 <Switch> </Switch> 组件,它需要将所有的 <Route /> 因此,它将一次只渲染一条路径。

对于所有的组件,我们总是需要设置 exact bool,这样就不会弄错 route='/'route='/about' 它们都具有 / 角色,或者说如果我们有这样的路线。/about/about/blabla. 因此,开关将知道什么 <Route /> 来渲染。

如果你想有一个 <NotFoundPage /> 组件的链接不存在。你只需要为一个不存在的链接分配 component prop<Route /> 组件,如

<Switch>
  <Route exact path='/' />
  <Route exact path='/about' />
  <Route component={NotFoundPage} />
</Switch>

0
投票

不知为何,我的 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;
推荐问答
热门问答
最新问答