Реагировать: как обернуть компонент со специальной? (доступ к свойству входа через компоненты)


У меня есть приложение react (с redux & react-router), которое в разных точках должно знать, вошел ли пользователь в систему на основе состояния некоторых данных в магазине и куча других вещей, связанных с данными в магазине.

Чтобы достичь этого, я создал компонент более высокого порядка, такой как:

import React from 'react';
import {connect} from 'react-redux';

export function masterComponent(Component){

  class MasterComponent extends React.Component {

    constructor(props){
      super(props);
    }

    loggedIn(){
      return this.props.player.token? true : false
    }

    render(){
      return (
        <Component {...this.props} player={{loggedIn: this.loggedIn()}}/>
      );
    }
  }

  UserComponent.propTypes = {
    player: React.PropTypes.object
  };


  function mapStateToProps(state) {
    return state;
  }

  return connect(
    mapStateToProps
  )(MasterComponent);

}

Мой вопрос в том, как лучше всего обернуть это вокруг моих отдельных компонентов? В настоящее время я реализовал его так, чтобы каждый отдельный компонент был обернут при передаче для подключения что прекрасно работает, но кажется немного неэффективным. ie:

import {masterComponent} from '../HigherOrderComponents/MasterComponent';

export class ResultsPage extends React.Component {

  constructor(props){
.....
  }


  render(){
    return (
       .....
    );
  }
}



export default connect(
  mapStateToProps,
  mapDispatchToProps
)(masterComponent(ResultsPage));

Есть ли лучший способ сделать это?

1 2

1 ответ:

Это действительно зависит от вашего варианта использования, я вижу 3 возможных решения. Приведенный ниже код является непроверенным и полу-псевдо.

Ваше первоначальное предложение, рефакторинг

export function masterComponent(Component) {

  const MasterComponent = (props) => {
    const loggedIn = props.player.token? true : false;

    // initial solution would override player, so you need 
    // something like this
    const player = { 
      ...this.props.player,
      loggedIn,
    };

    return <Component {...this.props} player={player} />
  }

  // Important! Here is the crucial part of the refactoring, 
  // not the coding style changes. Map only the relevant 
  // state properties, otherwise the component would rerender 
  // whenever any state property changed. 
  return connect(state => ({ player: this.state.player }))(MasterComponent);
}

Redux Middleware (мой личный выбор)

function loginMiddleware() {
  return store => next => action => {
    if (action.type === 'ADD_CREDENTIALS') {
      const { player } = store.getState();
      loginService.setPlayer(player);
    }

    // removePlayer if action.type === 'LOGOUT';

    return next(action);
  }
}

И в любом компоненте вы можете использовать

loginService.getPlayer() 

Чтобы проверить, вошел ли кто-то в систему или нет

Недостаток по сравнению с вашим подходом: если действие 'ADD_CREDENTIALS' было отправлено, но компонент, который запрашивает loginService.getPlayer(), не будет повторно отправлен / обновлен, вы можете оказаться в непоследовательном состоянии. Я уверен, что вы могли бы решить эту проблему с более конкретными знаниями вашего приложения.

Контекст (мой наименее любимый)

Используйте Reactcontext и передайте желаемое свойство всем другим компонентам.