Редиректы в React
Есть 2 способа сделать редирект на нужнаю страницу:
- через «Redirect to…», который импортируем из библиотеки react-router-dom. Синтаксис:
<Redirect to={"/login"} />
- через «props.history.push…», который является методом у history, приходящего по умолчанию вместе с пропсами. Синтаксис:
props.history.push("/login");
либоthis.props.history.push("/login");
Редирект через «Redirect to…» (из библиотеки react-router-dom)
- Импортируем функцию Redirect из библиотеки react-routerreact-router-domdom:
import {Redirect} from "react-router-dom";
- Перед return компоненты прописываем теперь редирект на нужную другую страницу, зависимо от условия.
— для функциональной компоненты (файл DialogsContainer.jsx):... if (!props.isAuth) return <Redirect to={"/login"} /> return ( ...
— для классовой компоненты (файл ProfileContainer.jsx):
... render() { if (!this.props.isAuth) return <Redirect to={"/login"} /> return ( ...
Сам isAuth мы предварительно получили в пропсы через mapStateToProps:
let mapStateToProps = (state) => ({ profile: state.profilePage.profile, isAuth: state.auth.isAuth }); let WithUrlDataContainerComponent = withRouter(ProfileContainer); export default connect(mapStateToProps, {getUserProfile}) (WithUrlDataContainerComponent);
- Но так прописывать однотипный редирект для каждой компоненты – лишняя работа, дублирование кода и отсутствие удобного контроля. Поэтому создадим HOC, чтобы избавиться от этих недостатков. Сначала для большего понимания создадим компоненту-обертку прямо в файле, где и был у нас редирект (файл ProfileContainer.jsx):
... } let AuthRedirectComponent = (props) => { if (!props.isAuth) return <Redirect to={"/login"} /> return <ProfileContiner {...props} /> } let mapStateToProps = (state) => ({ profile: state.profilePage.profile, isAuth: state.auth.isAuth }); let WithUrlDataContainerComponent = withRouter(AuthRedirectComponent); export default connect(mapStateToProps, {getUserProfile}) (WithUrlDataContainerComponent);
Т.е. создав эту контейнерную компоненту AuthRedirectComponent для контейнерной компоненты, дальше мы используем ее – эту компоненту подключаем к роутер и потом конектим.
- Практически аналогичным образом поступаем и в DialogsContainer.jsx, создав тоже обертку.
- В итоге мы имеем 2 аналогичные обертки. И чтобы создавать такие обертки сделаем HOC – функцию, создающую контейнерные компоненты. Для этого создадим отдельный файлик по адресу src/hoc/withAuthRedirect.js:
import React from 'react'; import {Redirect} from 'react-router-dom'; import { connect } from 'react-redux'; let mapStateToPropsForRedirect = (state) => ({ isAuth: state.auth.isAuth }); export const withAuthRedirect = (Component) => { class RedirectComponent extends React.Component { render() { if (!this.props.isAuth) return <Redirect to='/login' /> return <Component {...this.props} /> } } let ConectedAuthRedirectComponent = connect(mapStateToPropsForRedirect) (RedirectComponent); return ConectedAuthRedirectComponent; }
Как видим, чтобы каждый раз не получать в местах применения редиректа isAuth из стейта, мы законектили наш HOC для получения этого объекта. В данном примере наш HOC withAuthRedirect классовый, хотя мог бы быть и функциональным.
- Теперь в файлах с компонентами, где мы применяем редирект при остутствии авторизации, мы экспортируем HOC из созданного файла и вызываем его, передав нужную компоненту в качестве параметра:
... } let AuthRedirectComponent = withAuthRedirect(ProfileContainer); let mapStateToProps = (state) => ({ profile: state.profilePage.profile }); let WithUrlDataContainerComponent = withRouter(AuthRedirectComponent); export default connect(mapStateToProps, {getUserProfile}) (WithUrlDataContainerComponent);
Теперь, как видим, мы не создаем вручную нашу контейнерную компоненту для редиректа, а также нам больше не нужно получать и передавать в пропсы isAuth.
- Применив compose мы можем еще более правильно и компактно применить этот HOC:
export default compose( connect(mapStateToProps, {getUserProfile, getStatus}), withRouter, withAuthRedirect )(ProfileContainer)
Редирект через «props.history.push…» (метод у history в пропсах)
В пропсах приходит, у которого есть метод push, позволяющий перенаправить на нужную страницу при вызове.
Пример (взято из componentDidMount() файла ProfileContainer.jsx, где проверяется залогинен ли пользователь и присваивается его id):
componentDidMount() { let userId = this.props.match.params.userId; if (!userId) { userId = this.props.authorizedUserId; if (!userId) { this.props.history.push("/login"); } }