Реагировать: как обернуть компонент со специальной? (доступ к свойству входа через компоненты)
У меня есть приложение 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 ответ:
Это действительно зависит от вашего варианта использования, я вижу 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 и передайте желаемое свойство всем другим компонентам.