使用 React Redux Router,我应该如何访问路由的状态?

With React Redux Router, how should I access the state of the route?

使用 react-router-redux,似乎获取路由信息的唯一方法是仅通过 props。这样对吗?

下面是我现在在我的应用程序中大致做的事情:

<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 使我的应用程序如此干净的情况下,必须在所有内容中传递 props 感觉就像是倒退了一大步。所以如果传递参数是正确的,我想知道为什么那更可取?

我提出这个问题的具体案例:

我有一个发送消息的 UserInput 组件(调度 SEND_MESSAGE 操作)。根据当前页面(聊天室、消息提要、单个消息等),reducer 应将其放在正确的位置。但是,对于 react-redux-router,reducer 不知道路由,所以它不知道将消息发送到哪里。

为了解决这个问题,我需要传递道具,将 id 附加到我的 SEND_MESSAGE 操作,现在简单的 UserInput 正在处理我的应用程序的业务逻辑。

而不是解决你的问题(如何读取状态),我将解决你的问题本身(如何根据当前路由调度不同的动作)。

让你的 UserInput 成为 presentational component。让我们接受 onSend prop,而不是在其中调度,它是所有者组件提供的回调。输入会调用 this.props.onSend(text) 而不知道任何关于 Redux 或路由的信息。

然后,使 MessageList 也是一个接受 onSendMessage 作为道具的展示组件,并将其转发给 UserInput。同样,MessageList 不知道路由,只会将其传递给 <UserInput onSend={this.props.onSendMessage} />

最后,创建几个 容器 组件来包装 MessageList 用于不同的用例:

ChatRoomMessageList

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)

现在您可以直接在路由处理程序中使用这些容器组件。他们将指定要分派的操作,而不会将这些细节泄露给下面的展示组件。让您的路由处理程序负责读取 ID 和其他路由数据,但尽量避免将这些实现细节泄露给下面的组件。在大多数情况下,当它们由 props 驱动时会更容易。


解决原始问题,不,如果您使用 react-router-redux,您不应该尝试从 Redux 状态读取路由器参数。来自 README:

You should not read the location state directly from the Redux store. This is because React Router operates asynchronously (to handle things such as dynamically-loaded components) and your component tree may not yet be updated in sync with your Redux state. You should rely on the props passed by React Router, as they are only updated after it has processed all asynchronous code.

有一些 experimental projects 在 Redux 中保留整个路由状态,但它们有其他缺点(例如,React Router 状态是不可序列化的,这与Redux 是如何工作的)。所以我认为我上面写的建议应该可以很好地解决你的用例。