模块化是管理动态表单校验状态的核心思路——将表单拆分为独立、可复用、自带校验逻辑的字段单元,通过统一状态容器按需订阅与联动响应,支持动态规则变更、条件校验及列表项唯一ID管理。

模块化是管理动态表单校验状态的核心思路——把表单拆成独立、可复用、自带校验逻辑的单元,再通过统一的状态协调机制联动响应。
校验逻辑下沉到字段模块
每个表单项(如手机号输入框、多选标签组、日期范围选择器)封装自己的校验规则、错误提示、异步验证触发时机和反馈方式。不依赖外部传入一堆 validator 函数,而是内部定义 isValid()、validate() 和 getErrorMessage() 方法。
- 输入框模块内置防抖后的手机号正则校验 + 后端唯一性检查(失败时自动标记为 pending → error)
- 文件上传模块自行判断大小、类型、数量,并在上传中禁用提交按钮
- 级联选择器模块只在校级数据加载完成且有值时才触发下级校验
状态容器统一收口,按需订阅
用一个轻量状态管理器(如 Zustand store 或自研 FormState 类)集中维护所有字段的 value、touched、valid、error 等状态。关键不是“全量监听”,而是让每个模块只订阅自己关心的状态片段:
- 字段模块通过 key(如 "user.phone")注册自身状态,store 自动创建响应式子路径
- 提交按钮模块只订阅 form.isValid,它由 store 内部根据所有字段 valid 值聚合计算得出
- 全局错误摘要模块订阅 form.errors,它是一个扁平化的 {key: message} 对象
动态增删字段时保持校验上下文一致
列表型字段(如多个联系人、多张发票)不能简单用 index 当 key。应为每项生成唯一 ID(如 uuidv4),并让其子字段 key 带上该 ID:
- 新增联系人 → 分配 id="cont-abc123" → 其电话字段 key 为 "contacts.cont-abc123.phone"
- 删除时,store 清理以该 id 为前缀的所有状态键,避免残留校验态干扰新项
- 拖拽排序后,仅交换各 id 对应的数据位置,字段 key 不变,校验状态自然保留
支持运行时规则变更与条件校验
模块化结构天然适配规则动态注入。例如“是否为企业用户”开关变化时:
- 触发 store 的 updateRules({ 'company.name': requiredIf(isCorporate) })
- 对应字段模块收到规则更新通知,立即执行一次 validate() 并刷新 UI
- 隐藏字段(如非企业用户不显示税号)仍保留在状态树中,但设置 hidden: true,校验逻辑照常运行(避免提交时漏校验)
不复杂但容易忽略:模块间通信不走 props 深层透传,也不靠全局事件;靠状态容器提供精准的 key 路径访问能力 + 字段模块自身的自治校验闭环。这样既解耦,又可控。










