更新:这是一个例子
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}
/>
我已经尝试了几件事,但这是最近的一张照片:
我正在获取 reset
、change
以及默认属性中的其他内容。我正在按要求传递 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(...)
'事件。但是,在 handleSubmit()
运行并提交表单之前,表单和状态值不会更新。
我认为这可能与优先提交事件有关?
我也尝试过一些简陋的东西,比如导入change
(容器的默认属性)并定义重置按钮:
<button
name="reset_filters_button"
type="button"
onClick={() => {
change('organization_name', '');
methodThatDispatchesSubmitAction();
}}
disabled={pristine || submitting}
>
Clear Search
</button>
哪个(如果我删除 methodThatDispatchesSubmitAction()
)可以正常工作以将字段值设置回空白,从而使表单在技术上也再次“原始”。
methodThatDispatchesSubmitAction()
(如果不是很明显)通过 dispatchToProps
绑定(bind)到父级,并传递到表单容器,它使用“远程提交”建议,例如,
// organization_list_filter == name of the Redux-Form to submit.
dispatch(submit('organization_list_filter'));
TL;DR 和最后一个问题:
如何正确地重置表单并提交其默认值/空值?
每次我分派(dispatch)或直接调用 Redux 表单“提交”时,它都会在 从状态或 UI 清除值之前提交表单。 我已经使用调试器完成了这个,它没有跳过我对 reset
或 change
的调用。这就像一个异步/竞争问题,但我承认在这个特殊情况下我肯定不在我的联盟中。
我是不是直接做错了?
最佳答案
这绝对是一个竞争条件问题(或者因为我们实际上不是在处理线程,所以是事件顺序问题)。
使用 methodThatDispatchesSubmitAction
的原因是当您当前的示例不起作用时,是因为分派(dispatch)的操作具有直接从 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
Action 绑定(bind)到一个单独的调度中。虽然老实说,这与选项二相同,只是简化为一次调度。选项四,不要对所有数据使用 redux。显然,这第四个选项需要权衡取舍,但我的观点是,仅仅因为你在项目中使用 redux 并不意味着每一个数据都需要在 redux 中。尽管它完全违背了 redux-forms 的目的。
我还应该补充一点,您并不是唯一对此感到困惑的人。当您引入 redux 时,它会扰乱您传统上使用代码的方式。通常你认为,我先做 A,然后做 B。但是对于 redux,你做 A,等待 A 的更改通过系统,然后你做 B。这就是 Sagas 或 Thunks 可以很好的地方。您将更多逻辑移至 store 以对调度进行操作,而不是等待它全部通过 props 返回到组件。
关于javascript - 使用 Redux-Form 进行搜索过滤器,我如何才能 "reset"并重新提交表单?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56352136/