使用 Redux-Form 进行搜索过滤器,如何“重置”并重新提交表单?

Posted

技术标签:

【中文标题】使用 Redux-Form 进行搜索过滤器,如何“重置”并重新提交表单?【英文标题】:Using Redux-Form for search filters, how can I "reset" and re-submit the form? 【发布时间】:2019-10-14 13:38:21 【问题描述】:

更新:这是一个示例笔

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

前言

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

上下文

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

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

目前唯一的字段是“organization_name”,一个文本字段,用于设置查询参数值,并触发/endpoint?name=some_name的API请求。

例如,

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

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

我正在从默认道具中获取resetchange 和其他内容。我根据需要传递了handleSubmit

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

我想要/期望什么

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

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

<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() 运行并提交表单。

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

我也尝试过一些简单的东西,比如导入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' 时,它都会在从 state 或 UI 清除值之前提交表单我已经使用调试器完成了此操作,它并没有跳过我对 resetchange 的调用。这就像一个异步/竞争问题,但我承认在这种特殊情况下,我肯定不在我的联盟中。

我是不是直接做错了?

【问题讨论】:

【参考方案1】:

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

使用methodThatDispatchesSubmitAction 的原因在您当前的示例不起作用时,是因为调度的操作具有直接从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 全部返回到组件。

【讨论】:

(1) 需要明确的是,当我使用dispatch(reset()); dispatch(thingThatSubmits()) 时,我遇到了同样的问题。 (2) 真正的问题:setImmediate 似乎在 MDN 中附加了很多警告...引起关注? (3) 潜在的解决方法:重写resetAndSubmit 似乎可以解决问题。想法? const resetAndSubmit = async (event) =&gt; await reset(); handleSubmit() 另外,很抱歉这不是第一个出现的:感谢您写出如此详细的答案。它绝对帮助我解决了这个问题,给了我更多了解的术语,并帮助填补了我认为可能发生的事情但没有完全理解的知识空白。这个答案对我个人来说非常有帮助。 如果您担心 setImmediate,可以使用值为 0 的 setTimeout。你也可以使用 polyfills 来确保它可用。如果您使用的是 redux-promise 或 redux-thunk,那么我相信您可以等待调度,这将是一个很好的解决方案。

以上是关于使用 Redux-Form 进行搜索过滤器,如何“重置”并重新提交表单?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过重新选择使用 redux-form

如何使用标准构建器使用多个过滤器进行搜索

如何使用 redux-form 在不同组件(向上一个组件)中显示 FieldArray 中的字段

使用过滤器时如何使用 django_tables2 进行搜索

如何选择过滤器并使用选定的值在 vue 应用程序中进行搜索?

如何使用两个组件通过搜索进行过滤 [reactjs]