С React Redux Router, как мне получить доступ к состоянию маршрута?

С react-router-redux кажется, что единственный способ получить информацию о маршрутизации — только через реквизиты. Это правильно?

Вот примерно то, что я делаю в своем приложении прямо сейчас:

<Provider store={Store}>
  <Router history={history}>
    <Route path="/" component={App}>
      <Route path="child/:id" />
    </Route>
  </Router>
</Provider>

Приложение

const App = (props) => 
  <div className="app">
    <Header />
    <Main {...props}/>
    <Footer />
  </div>

Главный

const Main = (props) => 
  <div>
    <MessageList {...props}/>
  </div>

Список сообщений

let MessageList = (props) => {
  const {id} = props;

  // now I can use the id from the route
 }

const mapStateToProps = (state, props) => {
  return {
    id: props.params.id
  };
};

MessageList = connect(mapStateToProps)(MessageList)

Что бы я хотел сделать, так это удалить {...props} из всех моих компонентов и превратить MessageList в это:

let MessageList = (props) => {
  const {id} = props;

  // now I can use the id from the route
 }

const mapStateToProps = (state) => {
  return {
    id: state.router.params.id
  };
};

MessageList = connect(mapStateToProps)(MessageList)

Необходимость передавать реквизиты во всем кажется большим шагом назад по сравнению с тем, насколько чистым Redux сделал мое приложение. Итак, если передача параметров верна, мне интересно, почему это предпочтительнее?

Мой конкретный случай, который привел к этому:

У меня есть компонент UserInput, который отправляет сообщение (отправляет действие SEND_MESSAGE). В зависимости от текущей страницы (комната чата, лента сообщений, отдельное сообщение и т. д.) редьюсер должен поместить ее в нужное место. Но с помощью react-redux-router редуктор не знает о маршруте, поэтому он не может знать, куда отправить сообщение.

Чтобы исправить это, мне нужно передать реквизиты, прикрепить идентификатор к моему действию SEND_MESSAGE, и теперь простой в остальном пользовательский ввод обрабатывает бизнес-логику для моего приложения.


person Jason D    schedule 27.02.2016    source источник


Ответы (1)


Вместо того, чтобы решать ваш вопрос (как читать состояние), я решу саму вашу проблему (как отправлять различные действия в зависимости от текущего маршрута).

Сделайте свой UserInput презентационным компонентом. Вместо диспетчеризации внутри него пусть принимает свойство onSend, которое является обратным вызовом, предоставляемым компонентом-владельцем. Ввод вызовет this.props.onSend(text), ничего не зная о Redux или маршрутах.

Затем сделайте MessageList также презентационным компонентом, который принимает onSendMessage в качестве реквизита и перенаправляет его в UserInput. Опять же, MessageList не будет знать о маршрутах и ​​просто передаст их <UserInput onSend={this.props.onSendMessage} />.

Наконец, создайте пару компонентов контейнера, которые обертывают MessageList для разных вариантов использования:

ЧатКомнатаСписокСообщений

const mapDispatchToProps = (dispatch) => ({
  onSendMessage(text) {
    dispatch({ type: 'SEND_MESSAGE', where: 'CHAT_ROOM', text })
  }
})

const ChatRoomMessageList = connect(
  mapStateToProps,
  mapDispatchToProps
)(MessageList)

FeedMessageList

const mapDispatchToProps = (dispatch) => ({
  onSendMessage(text) {
    dispatch({ type: 'SEND_MESSAGE', where: 'FEED', text })
  }
})

const FeedMessageList = connect(
  mapStateToProps,
  mapDispatchToProps
)(MessageList)

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


Отвечая на исходный вопрос, нет, вам не следует пытаться читать параметры маршрутизатора из состояния Redux, если вы используете react-router-redux. Из README :

Вы не должны читать состояние местоположения непосредственно из магазина Redux. Это связано с тем, что React Router работает асинхронно (для обработки таких вещей, как динамически загружаемые компоненты), и ваше дерево компонентов может еще не обновляться синхронно с вашим состоянием Redux. Вы должны полагаться на реквизиты, переданные React Router, поскольку они обновляются только после обработки всего асинхронного кода.

Есть несколько экспериментальных проектов, которые делают сохранение всего состояния маршрутизации в Redux. но у них есть и другие недостатки (например, состояние React Router не сериализуемо, что противоречит тому, как работает Redux). Поэтому я думаю, что предложение, которое я написал выше, должно прекрасно решить ваш вариант использования.

person Dan Abramov    schedule 27.02.2016
comment
Что, если у меня есть несколько вложенных Container Component, которые не созданы напрямую Router? Таким образом, невозможно получить доступ к параметрам маршрутизатора, даже если я использую withRouter? Если я не могу создать несколько вложенных Container Component, можно отправить много реквизитов с уровня Router глубоко в мой вложенный компонент. - person aisensiy; 12.08.2016
comment
К вашему комментарию. Да. Переместите контейнер туда, где он вам нужен. - person Adrian Lynch; 18.11.2016