如何同步Redux状态和url查询参数


77

我有一个带有搜索面板的网页。搜索面板有几个输入字段:id,size,...

我想要的是用户设置搜索值(例如:id = 123和size = 45)并按下搜索按钮时:

  1. Redux reducer中的searchState应该使用新的搜索值(id = 123和size = 45)进行更新
  2. 网址应更改为“ http:// mydomain / home?id = 123&size = 45

另一方面,如果用户将URL更改为http:// mydomain / home?id = 111&size = 22,则:

  1. reducer中的searchState应该使用新的搜索值(id = 111和size = 22)进行更改
  2. UI搜索面板输入应更新为新值(id = 111和size = 22)

如何达成目标?我应该使用什么路由器(react-router,redux-router,react-router-redux或其他)?

Answers:


71

我建议直接使用React Router不要保留searchStateRedux。React Router将URL参数注入到您的组件中,您可以使用它们mapStateToProps(state, ownProps)来计算最终的道具。

如果您确实希望将路由更改视为操作,则可以使用react-router-redux进行双向同步,但是它不会为您提供状态中的参数-只是当前位置。如果要记录和重播动作,并在重播它们时更新URL栏,则它的唯一用例是。

完全没有必要-在大多数情况下,仅使用React Router就足够了。


大家好,@ Dan,我们面临着一个非常类似的问题,例如Anton。您的答案很有希望,但是我们很难找到一个很好的例子,在该例子中,React Router甚至是React Router与Redux结合使用时,只能为多个不同的URL更改一个组件的状态。在我们的示例中,我们更改了哈希标签,并且应始终将其仅应用于一个组件。
JoKer '16

1
有一条路由,并使用props路由器注入来控制此组件?这实际上是一个与Redux无关的独立问题,您可能需要单独询问。
Dan Abramov

好的,我将尝试创建一个新问题,在此我将更详细地解释我的问题。感谢您这么快回答。
JoKer '16

1
这是我的新问题。如果您可以看一下,那将是非常好的。stackoverflow.com/questions/36722584/...
JOKER

如何在选择器中使用路由参数呢?不得不将其从组件发送到选择器中似乎有点可笑,并且可能导致大量重复
Benja

17

简而言之:您可以使用redux-query-sync来同步存储中的URL参数和字段。它无需路由器即可工作。


更长的故事:在遇到相同问题时,我首先感谢Dan Abramov的回答,建议(以我的话)将URL视为“第二存储区”,这是Redux存储区之外应用程序状态的一部分。但是后来我发现拥有两种“商店”使修改代码(例如将事物从一个移到另一个)变得困难,因为每个“商店”都有不同的接口。作为开发人员,我希望选择Redux状态下的任何字段,并将其显示在URL中,就像该位置是我的状态(一部分)的小窗口一样。

因此,我刚刚发布了redux-query-sync,让您提供一个选择器功能,用于从状态中选择一个值,然后将其显示在窗口位置的指定参数名中。为了也使它在另一个方向上同步(即从URL到Redux状态)(例如,当应用程序最初加载时),您可以提供一个将被传递参数值的操作创建者,以便您的reducer可以相应地更新状态。


2

这是我处理第一种情况的方式:

  • 当输入值更改时,其组件将触发一个回调,该回调作为道具从其容器传递。

  • 在回调中,容器在事件发生时调度负责更新Redux状态的操作。

  • 在紧接动作调用之后的行中,我使用this.context.router.push()带有正确查询字符串的url并将其传递给它。

我不确定这是正确的方法。我发现最好先更新URL,因为我认为查询字符串应该是状态的反映,而不是状态的反映。

关于相反的情况,我真的不确定。似乎手动设置URL会触发完全重新加载,但我可能会误会。

至于要使用的路由器,我本身就是使用React Router。在使用其他功能时,我并没有真正找到价值,而这一讨论对我来说是至关重要的。


我看到的这种方法的问题在于,一旦容器中有多个组件更改了url,它就会纠缠回叫和url参数更新。可以做到这一点在各组件,而不是使用回调到容器....
亚历Parij

2

我最近完成了与此类似的问题。我使用MobX作为我的商店,并使用redux-router作为我的路由器。(我对react-router做得很好,但是我需要在组件外部分派push操作-redux因为全局存储在这里很好用)

我的解决方案类似于cantera所描述的-我的路由器状态仅是表单状态的反映。这具有不必放弃表单状态而完全取决于路由器状态的额外好处。


在第一种情况下

1)我照常更新表单输入,这会触发结果组件中的重新呈现。

2)在componentDidUpdate()结果组件中,我使用表单道具构造更新的查询字符串。

3)我将更新的查询字符串推送到路由器状态。这纯粹是为了更新URL。


对于第二种情况

1)在onEnterRoute组件的挂钩中,我获得了可用的查询字符串并将其解析为初始表单值。

2)我用值更新我的商店。这仅用于页面第一次加载,并且路由器状态唯一指示表单状态的时间。


编辑:当您返回浏览器历史记录时,此解决方案无法解决问题,因为该网址不会更新您的状态。



2

我最近还完成了针对我公司的应用程序的此功能的工作。我们想向URL添加不同的搜索查询。

我想在这里分享几件事:

1)我们使用了Redux存储和react-router。由于我们还使用了Typescript,因此最终使用了react-router的RouteComponentProps来使用this.props.history.push()更新URL。

2)我们将所有搜索查询保留在Redux存储中。更新Redux存储然后更新URL的工作流程如下:

在应用程序中选择一些过滤选项=>调度操作以更新Redux存储中的过滤状态=>更新URL

3)最后,我们还希望用户能够输入带有查询参数的URL,它将更新应用程序中的所有过滤器。为此,工作流程更加简单:

用户输入URL =>调度操作,以使用URL中的查询参数更新Redux状态。Redux状态的更新将自动导致应用中的重新渲染,并且所有过滤器都会更新。

因此,这里最重要的是始终保持Redux状态和URL彼此同步。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.