Редиректы в 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)

  1. Импортируем функцию Redirect из библиотеки react-routerreact-router-domdom:
    import {Redirect} from "react-router-dom";
  2. Перед 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);
    
    
  3. Но так прописывать однотипный редирект для каждой компоненты – лишняя работа, дублирование кода и отсутствие удобного контроля. Поэтому создадим 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 для контейнерной компоненты, дальше мы используем ее – эту компоненту подключаем к роутер и потом конектим.

  4. Практически аналогичным образом поступаем и в DialogsContainer.jsx, создав тоже обертку.
  5. В итоге мы имеем 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 классовый, хотя мог бы быть и функциональным.

  6. Теперь в файлах с компонентами, где мы применяем редирект при остутствии авторизации, мы экспортируем HOC из созданного файла и вызываем его, передав нужную компоненту в качестве параметра:
    ...
    }
    
       let AuthRedirectComponent = withAuthRedirect(ProfileContainer);
    
       let mapStateToProps = (state) => ({
          profile: state.profilePage.profile
       });
    
    let WithUrlDataContainerComponent = withRouter(AuthRedirectComponent);
    
    export default connect(mapStateToProps, {getUserProfile}) (WithUrlDataContainerComponent);

    Теперь, как видим, мы не создаем вручную нашу контейнерную компоненту для редиректа, а также нам больше не нужно получать и передавать в пропсы isAuth.

  7. Применив 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");
           }
       }

 

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *