首页 > 解决方案 > 使用 Redux-Form 进行搜索过滤器,如何“重置”并重新提交表单?

问题描述

更新:这是一个示例笔

https://codepen.io/anon/pen/vwzGYY?editors=0011

前言

根据我的研究,我似乎需要一种完全不同的方法。也许你可以推荐一个?

语境

我正在使用 Redux-Form(技术上是旧版本,但相关 API 似乎非常稳定。当我们到达那里时,我们可以烧掉那座桥。)为某种搜索结果列表设置一些“过滤器”。

特别是,由于我希望页面可以链接,我还通过 React-Router 在 URL 查询参数中设置表单内容,或者通过类似机制在页面加载时初始设置它。

到目前为止唯一的字段是“organization_name”,一个文本字段,用于设置查询参数值,并触发对/endpoint?name={some_name}.

例如,

<Field
  name="organization_name"
  component="input"
  type="text"
  placeholder="Organization Name"
  value={value}
/>

我已经尝试了几件事,但这是最近的一个镜头:

我正在从默认道具中获取reset,change和其他内容。我正在handleSubmit按要求传递。

handleSubmit工作正常,进行一些状态更新,使用 React Router 设置/推送 URL 查询参数,然后进行新的 API 调用/更新显示新结果!哇!

我想要/期待的

从长远来看,我想要一个“重置过滤器”按钮,它将所有过滤器值设置回默认值(例如,将“名称”值设置为空字符串),并重新提交表单(从而触发句柄提交)。

我首先尝试实现的是一个按钮,例如:

<button
  name="reset_filters_button"
  type="button"
  onClick={resetAndSubmit}
  disabled={pristine || submitting}
  >
    Clear Search
</button> 

resetAndSubmit表单容器上定义的位置如下:

const resetAndSubmit = event => {
  reset();
  handleSubmit();
};

实际发生了什么......(提交优先于调度的事件?)

使用 Chrome 开发工具调试器,我可以清楚地看到reset方法被调用,并返回它的dispatch(...)'d 事件。但是,表单和状态值在运行和提交表单之前不会更新。 handleSubmit()

我认为这可能与优先提交事件有关?

我还尝试了一些 janky 的方法,例如导入change(容器的默认道具)并定义重置按钮:

<button
  name="reset_filters_button"
  type="button"
  onClick={() => {
    change('organization_name', '');
    methodThatDispatchesSubmitAction();
  }}
  disabled={pristine || submitting}
>
  Clear Search
</button>

哪个(如果我删除methodThatDispatchesSubmitAction())可以正确地将字段值设置回空白,从而使表单在技术上也再次“原始”。

methodThatDispatchesSubmitAction()(如果不明显)通过 绑定在父级上dispatchToProps,并传入表单容器,在该容器中使用“远程提交”建议,例如,

// organization_list_filter == name of the Redux-Form to submit. 
dispatch(submit('organization_list_filter')); 

TL;DR 和最后一个问题:

如何正确重置表单并提交其默认/空值?

每次我分派或直接调用 Redux Form 'submit' 时,它最终都会在从状态或 UI 中清除值之前提交表单。我已经用调试器完成了这个,它没有跳过我对resetor的调用change。这就像一个异步/种族问题,但我承认在这种特殊情况下我肯定不在我的联盟中。

我只是直接做错了吗?

标签: javascriptreactjsreduxredux-form

解决方案


这绝对是一个竞争条件问题(或者因为我们实际上并没有处理线程,所以事件顺序问题)。

methodThatDispatchesSubmitAction当您当前的示例不使用时,使用 a 的原因是因为调度的操作具有直接从 redux 存储读取数据的好处。您的示例不是从 redux 存储中读取,而是从传入的属性中读取。是的,该属性来自 redux 存储,但您看到的问题是它尚未在您的组件中更新。

请耐心等待,因为下一篇文章不会完全准确,但足以解释您所看到的内容。

Submit is clicked
    -> Reset action is dispatched
       -> Reducer receives action and returns updated state
    -> Handle submit is fired using values prop (old state data still)
Component is updated with new props from redux state

如您所见,在我们的点击代码完成运行之前,事件的顺序不允许向属性提供更新的状态。如果你曾经看过 JS 事件循环的视频(我强烈推荐它),你就会知道我们的 onClick 句柄将在任何其他异步操作(或我们点击之后的同步操作)有机会之前完全运行跑步。

为什么没有立即为组件提供更新的 props 有充分的理由,但主要原因是性能。您可以通过将 handleSubmit 包装在一个立即触发的异步事件中来看到这个顺序实际上是问题所在(它实际上并没有立即触发,所有其他同步/异步操作在它完成之前排队)。

const resetAndSubmit = (event) => {
  reset();
  setImmediate(() => handleSubmit());
}

这会改变事件的顺序,如下所示:

Submit is clicked
    -> Reset action is dispatched
       -> Reducer receives action and returns updated state
    -> Handle submit is queued on the event loop (not run yet)
Component is updated with new props from redux state
Event loop reaches queued code and runs is
    -> Handle submit is fired using values prop (new state data)

希望这可以帮助您了解问题发生的原因。至于解决它的解决方案。显然,您可以将句柄提交排队,如上所示。另一种选择是您所描述的使用调度执行提交的选项。第三种选择是使用更重的东西,比如 redux-thunk 或 redux-sagas,将resetAndSubmit动作绑定到单个调度中。虽然老实说,这与选项二相同,只是简化为一次调度。选项四,不要对所有数据使用 redux。显然,这第四个选项需要权衡取舍,但我的观点是,仅仅因为您在项目中使用 redux 并不意味着每条数据都需要在 redux 中。尽管它完全违背了 redux-forms 的目的。

我还应该补充一点,你并不是唯一一个对此感到困惑的人。当您介绍 redux 时,它会与您传统上使用代码的方式相混淆。通常你认为,我先做 A 然后 B。但是对于 redux,你做 A,等待 A 的更改通过系统,然后你做 B。这就是 Sagas 或 Thunks 可以很好的地方。您将更多逻辑移至 store 以对 dispatch 采取行动,而不是等待它通过 props 全部返回到组件。


推荐阅读