@vaskadogana
Frontend developer

Как работает dispath в React или как происходит подпись на обновление redux?

Добрый день.
Решил использовать сборку https://github.com/luigiplr/react-router-redux-rxj...
суть в том, что разбивает бандл на страницы. Но не могу разобраться как происходит подключение store к компоненту.
Подписал компонент на store, но компоненту всё равно, что store обновилось через dispatch.
если я вызываю action через props, вот так this.props.getTransports(), то обновление происходит. Но это совсем неудобно когда нужно общаться с сервером, приходится городить огород с промисами. Сейчас например, нужно отправлять получать вебсокеты, без dispatch это мягко говоря не удобно.

export function getTransports(){
//тут ее получаю от сервера
return{
		    	      type: 'GET_transport',
				setTransportData: data
	}
}


messageStatusssss
export default connect(
      state => ({
        TransportData: state.globalR.controlR.TransportData,
        login: state.globalR.authorizationR.login,
        token: state.globalR.authorizationR.token,
        messageStatus: state.globalR.authorizationR.messageStatus,
        messageStatusssss: state.globalR.authorizationR.messageStatusssss
      }), 
      dispatch => bindActionCreators(ActionCreator, dispatch)
)(controlPage)


насколько я разобрался основная фишка происходит в этой функции
export default function asyncRoute(getComponent, getReducers) {
  return class AsyncRoute extends Component {
    static contextTypes = {
      store: PropTypes.shape({
        dispatch: PropTypes.func.isRequired
      })
    }

    static Component = null
    static ReducersLoaded = false

    state = {
      Component: AsyncRoute.Component,
      ReducersLoaded: AsyncRoute.ReducersLoaded
    }

    componentWillMount() {
      const { Component, ReducersLoaded } = this.state
      const shouldLoadReducers = !ReducersLoaded && getReducers
      if (!Component || shouldLoadReducers) {
        this._componentWillUnmountSubject = new Subject()
        const streams = [
          Component
            ? Observable.of(Component)
                .takeUntil(this._componentWillUnmountSubject)
            : Observable.fromPromise(getComponent())
                .map(esModule)
                .map(Component => {
                  AsyncRoute.Component = Component
                  return Component
                })
                .takeUntil(this._componentWillUnmountSubject)
        ]

        if (shouldLoadReducers) {
          streams.push(
            Observable.fromPromise(getReducers())
              .map(module => esModule(module, true))
              .map(reducers => {
                this.context.store.dispatch(injectReducers(reducers))
                AsyncRoute.ReducersLoaded = true
//вот тут  store, за которым следят компоненты (насколько я понял), console.log(this.context.store)
//но как в него делать диспатч не могу понять, в store.getState(), показывается только 
//основной редюсер, в сборке он
//dummy редюсер в index.js я вместо него сделал combineReducer назвал globalR

              })
              .takeUntil(this._componentWillUnmountSubject)
          )
        }

        Observable.zip(...streams)
          .takeUntil(this._componentWillUnmountSubject)
          .subscribe(([Component]) => {
            if (this._mounted) {
              this.setState({Component})
            } else {
              this.state.Component = Component
            }

            this._componentWillUnmountSubject.unsubscribe()
          })
      }
    }

    componentDidMount() {
      this._mounted = true

    }

    componentWillUnmount() {
      if (this._componentWillUnmountSubject && !this._componentWillUnmountSubject.closed) {
        this._componentWillUnmountSubject.next()
        this._componentWillUnmountSubject.unsubscribe()
      }
    }

    render() {

      const { Component } = this.state
      return Component ? <Component {...this.props} /> : null
    }
  }
}


// в App я вот так объявляю какое хранилище подключать к компоненту
const Form = asyncRoute(() => import('./pages/form'), () => import('reducers/index.js'))
  • Вопрос задан
  • 1253 просмотра
Пригласить эксперта
Ответы на вопрос 2
@KnightForce
Я короче, не читал.
Кратко
Чтобы подписать используй библиотеку react-redux. Она за кулисами подпишет. В итоге:
export default connect(mapStateToProps, mapDispatchToProps)(App);


connect - присоединяет хранилище.
mapStateToProps - выделяет часть или весь state. Может ты хочешь выдать только одно какое-то поле.
mapDispatchToProps - все что здесь вернется - и будет диспатчить.

Пример:
function mapDispatchToProps(dispatch) {
	return {
		downloadTickets: ()=>{
			dispatch(actions.downloadTickets);
		},
		setSelectValues: (value)=>{
			dispatch(actions.setSelectValues(value));
		},
		setActvePage: (value)=>{
			dispatch(actions.setActvePage(value));
		},
	};
}

export default connect(mapStateToProps, mapDispatchToProps)(App);


В mapDispatchToProps под капотом передается dispatch, все что вернется из этой функции будет доступно в props.
props.downloadTickets
Ответ написан
@vaskadogana Автор вопроса
Frontend developer
вопрос остается открытым
Что касается сборки, то ларчик открывался просто.
в файле store делаем export let store = createStore();
В файле entry импортим в провайдер этот store, вместо createStore()
ну и вместе dummy reducer делаем


p.s а так сбока лучшее решение, что я нашел для multipage aplication on clientside.
спасибо статье https://habrahabr.ru/company/Voximplant/blog/270593/
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы