首页 > 解决方案 > React Router onEnter 与 Redux 身份验证

问题描述

我正在尝试使用路由器的 onEnterreact-router-dom来验证用户是否经过身份验证。我将身份验证保留在登录减速器中。

初始状态:

const initialState = {
    logged: false,
    userName: null
}

在我的 App.js 我有我的路由器

import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";
import { useSelector } from "react-redux";
import Home from './Home';
import Login from './Login';

function App() {
  const login = useSelector((state) => state.login);

  const requireAuth = (nextState, replace, next) => {
      console.log(login)
    if(!login.logged) {
      replace({
        pathname: "/login",
        state: {nextPathname: nextState.location.pathname}
      });
    }
    next();
  }

  return (
    <Router>
      <Switch>
        <Route exact path="/" component={Home} onEnter={requireAuth} />
        <Route exact path="/login" component={Login} />
      </Switch>
    </Router>
  )
}

export default App;

它不会重定向到/login. 实际上,它没有调用requireAuth函数,因为浏览器没有显示函数内部的日志。我在路由器设置中缺少什么?顺便说一句,在导航到页面之前检查用户是否经过身份验证是否合适?

谢谢

使用更新的代码PrivateRoute。错误:Error: Maximum update depth exceeded.

import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Redirect
} from "react-router-dom";
import { useSelector } from "react-redux";
import Home from './Home';
import Login from './Login';

function App() {
  
  const PrivateRoute = ({ children, ...rest }) => {
    const login = useSelector((state) => state.login);
      console.log(login);
    return (
      <Route
        {...rest}
        render={({ location }) =>
          login.logged ? (
            children
          ) : (
            <Redirect
              to={{
                pathname: "/login",
                state: { from: location }
              }}
            />
          )
        }
      />
    );
  }

  return (
    <Router>
      <Switch>
        <PrivateRoute path="/">
          <Home />
        </PrivateRoute>
        <Route path="/login">
          <Login />
        </Route>
      </Switch>
    </Router>
  )
}

export default App;

标签: reactjsreduxreact-router-dom

解决方案


不,最好的方法是您可以在react-router 示例页面中看到的内容。

您最好像这样定义到您的私人页面的路线:

function PrivateRoute({ children, ...rest }) {
  const login = useSelector((state) => state.login);
  return (
    <Route
      {...rest}
      render={({ location }) =>
        login ? (
          children
        ) : (
          <Redirect
            to={{
              pathname: "/login",
              state: { from: location }
            }}
          />
        )
      }
    />
  );
}

然后像这样使用它:

<Switch>
    <Route path="/public">
       <PublicPage />
    </Route>
    <Route path="/login">
       <LoginPage />
    </Route>
    <PrivateRoute path="/protected">
       <ProtectedPage />
    </PrivateRoute>
</Switch>

更新:

你更新了你的帖子,对于那些可能犯这个错误的人:

在更新的代码中,我们有这个开关结构:

<Switch>
    <PrivateRoute path="/">
      <Home />
    </PrivateRoute>
    <Route path="/login">
      <Login />
    </Route>
</Switch>

当我们将用户重定向到/login页面时。它也与第一条路线 ( /) 匹配。所以Switch选择第一个PrivateRoute渲染,它会形成一个无限循环。

有两种方法可以解决这个问题:

首先:Switch层次结构中将更长和更具体的路线放在首位。例如在您的代码中,您可以这样做:

<Switch>
    <Route path="/login">
      <Login />
    </Route>
    <PrivateRoute path="/">
      <Home />
    </PrivateRoute>
</Switch>

第二:exact在更通用的路线中首先使用:

<Switch>
    <PrivateRoute exact path="/">
      <Home />
    </PrivateRoute>
    <Route path="/login">
      <Login />
    </Route>
</Switch>

推荐阅读