【问题标题】:How to dispatch redux actions using react-router v4?如何使用 react-router v4 调度 redux 操作?
【发布时间】:2018-07-16 16:58:28
【问题描述】:

我正在尝试结合 react-router v4、react 和 redux。因为 react-router 跟踪 URL,所以我选择将该状态保留在 redux-model 之外。

但是当 react-router 发生路由更改时,我仍然需要一种方法来调度 redux 操作。最好的地方在哪里?

我的第一次尝试是把它放在 react-router 的 Link 的 onClick 属性中:

render() {

  // link config
  const links = this.props.photo.album( album => {
    <Link key={album.name} 
             to=`/album/${album.name}`
             onClick={() => this.props.dispatchAction(album.name)} />
  })

  // route config
  return (
     <div>
         {links}
         <Route path={`/album/:albumName`} component={Album}/>
     </div>
  )
}

这个想法是,当用户点击一个链接时,dispatchAction() 将更新 redux 状态,然后加载 Album 组件。

问题在于,如果用户直接导航到 URL(例如 /album/a1),则永远不会分派操作,因为从技术上讲,永远不会点击链接。

因此,我删除了 Link 的 onClick 部分,并将 dispatchAction 移至 Album 组件的生命周期方法:

class Album extends Component {
    // invoked when user navigates to /album/:albumName directly
    componentDidMount() {
        this.props.dispatchAction(this.props.match.params.albumName)
    }

    // invoked whenever the route changes after component mounted
    componentWillReceiveProps(nextProps) {
        if (this.props.match.params.albumName != nextProps.match.params.albumName) {
            this.props.dispatchAction(nextProps.match.params.albumName)
        }
    ....
}

现在,每当安装 Album 组件或更改其属性时,它都会调度 redux-action。这是组合这些库的正确方法吗?

【问题讨论】:

    标签: javascript reactjs redux react-router


    【解决方案1】:

    react-router-redux 通过在您的商店中应用一个中间件来为您执行此操作,该中间件在路由更改以及初始路由更改时调度操作。这绝对是最干净的方法。

    唯一的缺点是它仍然是 alpha,但我们已经使用它一段时间了,没有任何问题。它也是 react-router 附加软件包 repo 的一部分。

    【讨论】:

    • 我看到 react-router-redux 将调度一个包含新 url 的 LOCATION_CHANGE 动作。我可以设置一个 reducer 来监听该操作并更新商店,但现在我必须解析出 url。 React-router 已经用它的 match 对象做到了这一点。有没有一种干净的方法可以在一个地方解析 url?
    • 你可以让你的 store 存储 react-router 保存的路由信息​​,并从你的 reducer 中读取所需的信息。
    • 我认为这可能是合并库的官方方式,但我最终从 react-router 切换到 redux-first-router。
    【解决方案2】:

    您可以创建一个自定义Route 组件,在componentDidMount 中调度您的操作:

    class ActionRoute extends React.Component {
      componentDidMount() {
        const { pathname } = new URL(window.location.href);
        const [albumName] = pathname.split('/').slice(-1);
        this.props.dispatchAction(albumName);
      }
    
      render() {
        return <Route {...this.props} />
      }
    }
    

    这将在路由加载时调度您的操作。可组合性 FTW!。

    旁注:如果您将ActionRoute 用于参数化路由(例如/album/1/album/2),您还需要在componentDidUpdate 中调度操作,因为如果组件未卸载/重新安装您从/album/1 导航到/album/2

    【讨论】:

    • 看起来 match.params 在 Route/ActiveRoute 中不可用。只有在路由发生后,react-router 才会填写 match.params 字段。
    • 你是对的,完全隔开。我已经更新了我的答案以手动从 url 中解析专辑名称。
    • 如果您对不自己进行解析感到非常强烈(这是有效的),那么您将调度放入路由呈现的组件中的方法与 imo 一样好。
    猜你喜欢
    • 2018-12-09
    • 2017-12-05
    • 1970-01-01
    • 2019-07-30
    • 2018-11-27
    • 2016-11-17
    • 1970-01-01
    • 2018-10-28
    • 2016-12-03
    相关资源
    最近更新 更多