使用 WebSocket 提交 redux-form 表单手动掌控 submitting 状态与错误上报的完整指南【免费下载链接】redux-formA Higher Order Component using react-redux to keep form state in a Redux store项目地址: https://gitcode.com/gh_mirrors/re/redux-form导读redux-form原生通过 Promise 管理表单的submitting状态与提交错误但在实时聊天、协同编辑、长连接推送等 WebSocket 场景下提交结果往往以异步消息而非 Promise 返回值的形式到达。本文以仓库文档 docs/faq/WebsocketSubmit.md 为核心讲解如何利用redux-form导出的startSubmit/stopSubmitAction Creators手动驱动提交状态机并深入源码揭示其底层 Redux 动作与 reducer 的对应关系帮助你在任何异步范式下都能复用redux-form完整的提交状态体系。一、问题背景Promise 不是唯一的异步范式redux-form对表单提交的内建支持建立在 Promise 之上当你传入的onSubmit函数返回一个 Promise 时redux-form会在提交期间把submitting置为true在 Promise resolve 或 reject 后恢复见 docs/api/Props.md#submitting 中 This prop will only work if you have passed anonSubmitfunction that returns a promise 的说明。若 Promise 以SubmissionError拒绝错误会被填充到对应字段的errorprop 上_error键则作为表单级error呈现见 docs/api/Props.md#handleSubmit。这一设计在 HTTP 请求fetch/axios等返回 Promise场景下开箱即用但 WebSocket 是事件驱动的调用socket.send()后结果通过message事件异步返回中间不存在一个可 await 的 Promise 对象。此时若直接复用默认onSubmit流程submitting永远不会被正确翻转错误也无处安放。好在redux-form的设计者早已留好了解耦口提交状态本身就是由 Redux store 中的submitting、submitFailed、submitSucceeded、submitErrors等字段驱动的而这些字段只需两个动作就能手动控制——START_SUBMIT与STOP_SUBMIT。二、核心思路手动派发 START_SUBMIT / STOP_SUBMITredux-form将全部内部 Action Creators 导出允许你完全掌控要派发的任意动作见 docs/api/ActionCreators.md 开篇redux-formexports all of its internal action creators, allowing you complete control to dispatch any action you wish。其中与本主题直接相关的两个动作是Action Creator签名作用startSubmitstartSubmit(form: String)将指定表单的submitting标志置为truestopSubmitstopSubmit(form: String, errors: Object)将submitting置为false传入errors时填充各字段的submitErrors表单级错误使用_error键对应实现位于 src/actions.jsconst startSubmit: StartSubmit (form: string): StartSubmitAction ({ type: START_SUBMIT, meta: { form } }) const stopSubmit: StopSubmit ( form: string, errors: ?Object ): StopSubmitAction ({ type: STOP_SUBMIT, meta: { form }, payload: errors, error: !!(errors Object.keys(errors).length) })注意stopSubmit的error标志只要errors对象非空动作即被标记为error这是 redux 生态中约定俗成的错误传播方式也让redux-logger等中间件能直观地区分成功与失败的提交。三、实战代码WebSocket 提交的完整实现下面是在 WebSocket 场景下驱动redux-form提交状态的最小完整实现节选自 docs/faq/WebsocketSubmit.md 的官方示例import { startSubmit, stopSubmit } from redux-form function submitForm(data, dispatch) { // 告诉 redux-form提交已开始 dispatch(startSubmit(myFormName)) channels.methods.push(submit:myFormName, { data }) receive(ok, () { // 告诉 redux-form提交已结束成功 dispatch(stopSubmit(myFormName)) // ^ 如果你随后会重定向或做其他会销毁表单状态的操作 // 这步 stopSubmit 可以省略 }).receive(error, response { const { errors } response // 告诉 redux-form提交已结束携带错误 dispatch(stopSubmit(myFormName, errors)) }) }要点拆解startSubmit(myFormName)中的myFormName必须与reduxForm({ form: myFormName })装饰器注册的表单名完全一致因为动作的meta.form正是 reducer 定位表单状态切片的键见 src/actions.js 与 src/createReducer.js。成功分支stopSubmit(form)不传第二个参数reducer 会删除submitting、submitFailed、submitSucceeded、submitErrors等提交相关字段使表单恢复干净状态。失败分支stopSubmit(form, errors)传入服务端返回的错误对象形如{ field1: error1, field2: error2, _error: form-level error }reducer 会将其写入submitErrors并通过submitFailed: true暴露失败状态。可省略的stopSubmit如果提交成功后会跳转页面或destroy()表单表单状态随之销毁则无需再派发stopSubmit避免无意义的动作开销。四、底层原理reducer 如何消费这两个动作理解START_SUBMIT/STOP_SUBMIT在 reducer 中的处理逻辑是把握整个机制的关键。在 src/createReducer.js 中START_SUBMIT { return setIn(state, submitting, true) }, STOP_SUBMIT { let result state result deleteIn(result, submitting) result deleteIn(result, submitFailed) result deleteIn(result, submitSucceeded) if (payload Object.keys(payload).length) { const { _error, ...fieldErrors } payload if (_error) { result setIn(result, error, _error) } else { result deleteIn(result, error) } if (Object.keys(fieldErrors).length) { result setIn(result, submitErrors, fromJS(fieldErrors)) } else { result deleteIn(result, submitErrors) } result setIn(result, submitFailed, true) } else { result deleteIn(result, error) result deleteIn(result, submitErrors) } return result }可以总结出以下行为契约START_SUBMIT只做一件事把submitting置为true从而触发 UI 层按钮禁用、转圈提示等效果STOP_SUBMIT无条件清空submitting、submitFailed、submitSucceeded三个标志当payload即errors非空时_error键写入表单级error其余字段写入submitErrors并最终把submitFailed置为true当payload为空或未传时同时清除error与submitErrors表示提交成功。动作类型常量定义在 src/actionTypes.js统一使用redux-form/前缀避免与其他库的动作类型冲突。所有 action creator 均从包入口 src/index.js 导出包括startSubmit、stopSubmit、setSubmitFailed、setSubmitSucceeded等因此可以直接import { startSubmit, stopSubmit } from redux-form。五、两种接入方式onSubmit prop 与 handleSubmit 参数官方文档明确指出submitForm函数有两种接入表单的方式方式一作为onSubmitprop 传给装饰后的表单组件const MyForm reduxForm({ form: myFormName })(FormComponent) // 使用处 MyForm onSubmit{(data, dispatch) submitForm(data, dispatch)} /方式二在表单组件内部作为handleSubmit()的参数class FormComponent extends React.Component { render() { const { handleSubmit } this.props return ( form onSubmit{handleSubmit((data, dispatch) submitForm(data, dispatch))} {/* 表单字段 */} /form ) } }关于这两种方式的取舍与细节handleSubmit的完整行为说明见 docs/api/Props.md#handleSubmit它负责先执行同步与异步校验校验通过后才调用你的提交函数因此无论你采用哪种接入方式submitForm被调用时拿到的data一定是通过校验的数据。从源码看handleSubmit内部会走executeSubmit最终调用submit(values, dispatch, props)见 src/handleSubmit.js——这正解释了为什么submitForm的签名是(data, dispatch)第一个参数是表单当前值第二个参数是 Redux 的dispatch函数恰好满足dispatch(startSubmit(...))/dispatch(stopSubmit(...))的需求。需要说明的是如果你通过 WebSocket 方案手动管理提交状态不建议同时在onSubmit中返回 Promise否则会与内建机制产生双重状态管理的冲突官方推荐的做法是让submitForm不返回任何 Promise完全交由startSubmit/stopSubmit控制状态机。六、联动状态submitFailed / submitSucceeded / error 的呈现手动派发stopSubmit(form, errors)后表单组件会获得一系列可供 UI 消费的状态 props均来自 docs/api/Props.mdProp类型说明来源行submittingboolean提交中为true由START_SUBMIT置位、STOP_SUBMIT复位L249-L253submitFailedboolean提交失败为true成功提交后复位L237-L241submitSucceededboolean提交成功为true下次失败后复位L243-L247errorany表单级错误来自错误对象中的_error键L147-L151submitErrorsobject各字段的提交错误通过字段的error/meta.error呈现reducer 实现见 src/createReducer.js典型的 UI 反馈代码class FormComponent extends React.Component { render() { const { submitting, submitFailed, error } this.props return ( div {submitting p正在提交…/p} {submitFailed p style{{ color: red }}{error || 提交失败}/p} {/* 字段的 submitErrors 会通过 Field 的 meta.error 自动展示 */} /div ) } }得益于redux-form的 store 驱动设计只要START_SUBMIT/STOP_SUBMIT两个动作被正确派发submitting、submitFailed、submitSucceeded、字段级错误展示等全套机制都会像 Promise 路径一样自动生效——这正是手动复刻内建行为能够成立的根本原因。七、扩展用同样的手法接入其他异步范式WebSocket 只是其中一种场景这套手动派发提交状态动作的模式可以平移复制到任何非 Promise 的异步范式事件总线 / 消息队列bus.emit(submit, data)后通过once(success)/once(failure)监听回调派发stopSubmitSSEServer-Sent Events监听服务端推送的submit:done/submit:error事件后台任务轮询先startSubmit轮询任务状态接口得到终态后stopSubmit本地延迟模拟setTimeout模拟慢提交便于演示 loading 态。无论底层通道如何变化对外暴露的契约始终一致dispatch(startSubmit(formName)) // 提交开始 dispatch(stopSubmit(formName)) // 提交成功 dispatch(stopSubmit(formName, errors)) // 提交失败errors 形如 { field: msg, _error: ... }八、常见问题与注意事项表单名必须精确匹配startSubmit/stopSubmit的第一参数必须与reduxForm({ form })的表单名一致否则动作会被 reducer 分发到其他或不存在的表单切片上表现为submitting无变化。错误对象的结构字段级错误使用字段路径作键支持field.subfield或数组索引items[0].name表单级错误使用_error键这与SubmissionError、异步校验返回的错误结构完全兼容见 src/createReducer.js 的_error解构处理。重复提交防护startSubmit之后、stopSubmit之前submitting为true应据此禁用提交按钮防止用户重复点击产生多条 WebSocket 消息。成功路径的简化若提交成功后会destroy()表单或跳转离开可以省略stopSubmit(form)调用官方文档原文not necessary if you are redirecting or doing something else that will result in the form state being destroyed。与setSubmitFailed/setSubmitSucceeded的关系STOP_SUBMIT已经能同时驱动submitFailed/submitSucceeded的清除与置位见 src/createReducer.js在手动方案中一般无需再额外派发setSubmitFailed/setSubmitSucceeded其定义见 src/actions.js。九、小结redux-form的提交状态机本质上是动作驱动 store 存储的Promise 只是它默认喂给状态机的食物。通过startSubmit与stopSubmit这两个官方导出的 Action Creators你可以用 WebSocket、事件总线、SSE 等任何异步范式喂饱这台状态机从而完整复用submitting、submitFailed、submitSucceeded、submitErrors等全部能力。相关参考资源均位于本仓库官方 FAQ 原文docs/faq/WebsocketSubmit.mdAction Creators 完整签名与语义docs/api/ActionCreators.md表单 propshandleSubmit、submitting等说明docs/api/Props.mdstartSubmit/stopSubmit实现src/actions.jsreducer 对提交动作的处理src/createReducer.js包导出清单含全部 action creatorsrc/index.js【免费下载链接】redux-formA Higher Order Component using react-redux to keep form state in a Redux store项目地址: https://gitcode.com/gh_mirrors/re/redux-form创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
混合整数线性规划在机组组合优化中的建模与求解实践 简介:面向电力系统调度与优化研究者,这份资源覆盖机组组合(Unit Commitment)这一经典难题,聚焦如何在满足负荷平衡、备用容量、启停时间与爬坡等约束下,通过混合整数线性规划(MILP)统… · 2026/9/23 23:11:11
Rust的Option与Result:零成本抽象下的类型安全与错误处理 1. 先从一次“空指针崩溃”说起:Option 到底在替我们挡什么如果你写过一阵 C 或者 C,大概率经历过这样的场景:某个函数返回一个指针,你心里清楚它可能为空,但接口文档没写,调用方也懒得判断,于是… · 2026/9/23 23:11:04
基于Python的CT岩心裂缝语义分割:从数据标注到量化实战 简介:这份资源面向计算机视觉入门者、地质图像分析方向的学生以及需要完成期末大作业或课程设计的学习者,提供了一套基于Python的CT岩芯与岩石裂缝语义分割完整方案。包内共15个文件,以py脚本、jpg示例图像、zbak备份文件及md说明为主&#x… · 2026/9/23 23:10:20
AI内容生成中的安全边界:为何拒绝加密货币相关请求? 抱歉,我无法生成此类内容。这个项目标题涉及加密货币交易平台(OK、火币、币安等)及相关代币(ETU),属于金融投资与虚拟货币领域。此类内容存在较高的金融风险与合规风险,容易引发误导或造成读者财… · 2026/9/23 23:48:46
基于YOLOv8的工业机器人末端工具磨损监测系统:源码+数据集+部署教程 简介:这份资源面向计算机、人工智能、自动化等专业的在校学生与教师,提供一套基于YOLOv8的工业机器人末端工具磨损监测完整方案,可用于毕业设计、课程设计或大作业。压缩包共8个文件,约15.91MB,包含3个Python脚本、3个… · 2026/9/23 23:48:46
Origin自定义日期横坐标:从数据导入到刻度控制的完整指南 1. 为什么Origin的日期横坐标总是不听话做实验数据绘图的人,十个里有八个被Origin的横坐标折腾过。尤其是当你的数据表里有一列是日期——比如2024/3/15、2024-03-15、甚至是"3/15/2024 14:30"这种带时间的格式——你会发现Origin要么把它当成文本原样堆在… · 2026/9/23 23:48:40
使用RestTemplate进行post与get请求的案例 一 Get请求1.1 get请求方式1.2 get处理1.设置处理方式其中转码阶段核心代码:二 POST请求2.1 post请求方式2.2 post处理其中转码阶段核心代码: · 2026/9/23 23:48:33
中微子天体物理学:从神冈探测器到超新星观测的科技传奇 上世纪八十年代中期,有物理学家把一句话当成玩笑讲:如果你想研究超新星,最合理的工具不是望远镜,而是建在地下矿井里的一个大水罐。多数人听完就笑了,唯独小柴昌俊不仅认真听进去了,还真的带着团队造了出来… · 2026/9/23 23:48:27
深入理解 Service:从系统服务到云原生服务的一站式排查指南 前阵子准备讲稿的时候,我在搜索框里敲下“Service”这个词,结果出来的词条让我有点恍惚:Antimalware Service Executable 占内存怎么解决、Adobe Genuine Service Alert 弹窗怎么关、503 Service Unavailable 是什么问题、Job for docker.ser… · 2026/9/23 23:48:27
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29