#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
свойство в корневом/
маршруте.