Реагируйте на маршрутизатор в центре с повторной аутентификацией

#reactjs #redux #react-router-dom

Вопрос:

Я пытаюсь использовать центр маршрутизатора от react-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;
 

Ответ №1:

нет, лучший подход-это то, что вы можете увидеть на странице примера react-маршрутизатора.

вам лучше определить маршрут к вашим личным страницам, как это:

 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>
 

Комментарии:

1. Из вашего примера, когда я пытаюсь получить доступ localhost:3000/login , он возвращается Error: Maximum update depth exceeded , потому что он вызывает PrivateRoute метод несколько раз

2. пробовать <PrivateRoute exact path="/"> . (добавьте точное ключевое слово)

3. помните, когда ваш URL- /login адрес совпадает с обоими указанными вами путями. ( / и /login ) и он выбирает первый из них, из-за компонента переключателя

4. Спасибо! Каждый путь, который я добавляю, будет соответствовать первому / ? В этом случае, должен ли я переместить / в конец Switch ?

5. да, или, как я обновил свой ответ, вы можете использовать exact свойство в корневом / маршруте.