首页 > 解决方案 > 将 queryParameters 与 Redux 状态同步并为功能组件做出反应路由器

问题描述

我正在寻找集成以下堆栈的最佳实践

基本上,我有一个带有复杂过滤器组件的搜索页面,该组件负责处理页面上的过滤可能性。这些过滤器由下拉列表和复选框组成。如果选择/取消选择过滤器,我会通过操作/事件调度程序/reducer 等保持它们的状态。一旦单击按钮提交,就会对 API 进行异步 HTTP 调用,这将在页面上显示适当的结果

目前一切都运行良好。

棘手的部分是我希望能够通过 URL 共享这些过滤后的搜索。我认为最好用查询参数更新 URL。如 /search?filter1=ok&filter2=true

一旦用户输入 URL,过滤器组件将读取查询参数并更新状态。但是状态如何根据用户的操作附加/删除 URL 查询参数呢?

我只是在寻找不太复杂的解决方案,如果可能的话,使用我当前依赖的能力(我应该使用钩子吗?)

我找到了各种解决方案,但主要基于容器组件,我试图通过钩子坚持使用功能组件。

提前感谢您的提示和想法。

安塞尔姆

标签: javascriptreactjsreduxreact-redux

解决方案


这个解决方案可能比你想要的更复杂,因为你已经有了代码,但这里是我如何在没有添加 2 路绑定和每个人似乎都喜欢这些问题的额外库的情况下解决了这个问题。

改变您的理念并将您的历史/网址视为您的过滤器状态,将允许您使用您喜欢的所有单向模式。使用 url 作为新的过滤器状态,附加效果将让您触发效果,例如将应用程序状态同步到 url、获取等。这使您的标准导航功能(例如链接、来回等)可以免费使用,因为它们将简单地通过效果进行过滤。假设您使用标准的 react-router/redux 堆栈,该模式可能看起来像这样,但可以适应使用您手头的任何东西。

const dispatch = useDispatch();
const location = useLocation();
const parse = (search) => {
  // parse search parameters into your filter object applying defaults ect.
};

useEffect(async () => {
  const filters = parse(location.search);

  dispatch({ type: 'SEARCH_START', payload: filters }); // set spinner, filters, ect.

  const response = await fetch(/* your url with your filters */);
  const results = await response.json();

  dispatch({ type: 'SEARCH_END', payload: results });

  // return a disposer function with a fetch abort if you want.
}, [location.search]);

此效果将解析并分派您的搜索操作。请注意它是如何直接从 读取值location.search、解析它们,然后将这些值传递给 redux 或您使用的任何状态管理以及获取的。

要处理您的过滤器更新逻辑,您的搜索操作只需要推送历史记录。这将为您提供单向流,使结果与 url 保持同步,并使 url 与用户过滤器保持同步。您不再直接更新过滤器,状态必须朝一个方向流动。

const useFilters = () => {
  const serialize = (filters) => {
    // exact opposite of parse. Remove default filter values or whatever you want here.
    // return your new url.
  };
  const history = useHistory();
  const filters = useSelector(selectFilters); // some way to find your already parsed filters so you can add to them.
  
  return {
    sortBy: (column) => history.push(serialize({ ...filters, sortBy: column })),
    search: (query) => history.push(serialize({ ...filters, query })),
    filterByShipping: (priority) => {} // ect,
    filterByVendor: (vendor) => {} // blah blah
  };
}

上面是一个钩子形式的过滤器 api 的例子。您可以使用useFilters()返回函数来更改 url。然后会触发效果,解析 url,触发新的搜索,并保存解析后的过滤器值,您可以在其他组件中使用。

parseandserialize函数只是将查询字符串中的值转换为过滤器并返回。这可以像您需要的那样复杂或简单。如果您已经在使用查询字符串库,则可以在此处使用它。在我的项目中,他们通常会解析诸如“q”之类的短键以进行查询,并返回一个单声道类型的过滤器值,如果它们未定义,则它们具有排序顺序等默认值。stringify/serialize 会做相反的事情。它会使用过滤器,将它们转换为短键,删除空值和默认值,然后输出一个搜索 url 字符串,我可以将其用于任何 urls/hrefs/ect。


推荐阅读