@formily/core 表单领域模型
1. 核心对象关系
Form:顶层聚合根,持有values/initialValues/fields/heart/graph。Field:基础数据字段,负责 value/validator/feedback/input 生命周期。ArrayField:在Field基础上增强数组操作 + 子节点状态转置。ObjectField:增强对象属性增删与子节点清理。VoidField:不参与数据提交,负责结构与 UI 控制。Query:按 path/address 模式查询字段集合。Graph:导入导出全量状态图(time-travel/快照场景)。Heart + LifeCycle:事件总线与生命周期 hook 执行器。
2. Form 的关键设计
2.1 values 与 initialValues 并存
Form 同时维护:
values:当前提交值initialValues:重置基线
并通过 observe 深监听触发:
ON_FORM_VALUES_CHANGEON_FORM_INITIAL_VALUES_CHANGE
2.2 “字段值不单独存储”的幂等策略
Field.value 实际读写的是 form.values[path]。
这保证“字段状态与提交数据”天然一致,避免双写源引发不一致。
2.3 延迟更新队列(字段尚未出现时)
setFieldState 如果没匹配到字段,会通过 subscribeUpdate 进入更新队列,等字段初始化后应用。
这是动态渲染表单非常关键的“最终一致性”机制。
3. Field 的关键规则
3.1 address 与 path 双路径
address:节点绝对路径(包含 VoidField 层级)path:数据路径(跳过不影响数据结构的 Void 层)
这就是为什么同一字段可被两类路径查询命中。
3.2 display 语义不是简单布尔
visible:显示,数据存在hidden:隐藏,数据保留none:隐藏,数据从 values 移除(并可缓存回写)
Field.makeReactive 对 display 切换有专门的缓存写回逻辑。
3.3 modified 传播
modifySelf 不只改当前字段,还会向父级数据字段与 form 传播 modified=true,用于“用户是否真实改动过”的语义判断。
3.4 feedback 与 validator 结果隔离
validate 产出的反馈 code 与 effect 人工写入的反馈 code 分离(Validate* vs Effect*),避免污染。
4. ArrayField / ObjectField 的难点
4.1 ArrayField 不只改值,还要改“字段图”
spliceArrayState/exchangeArrayState 会同步迁移或删除子字段节点,保证:
- 数组值顺序变更;
- 字段状态(错误、脏态、组件 props)也随索引迁移。
这也是 Formily 做“复杂动态数组表单”比手写方案稳的关键。
4.2 ObjectField 的 additionalProperties 跟踪
addProperty/removeProperty 会维护 additionalProperties 集合,并在 key 变化时清理已失效子节点。
5. 提交、校验、重置的统一编排
batchSubmit / batchValidate / batchReset 统一由 internals 编排:
- 自动切换
submitting/validating/loading; - 触发完整生命周期;
- 在 form/field 两级都可复用同一套行为。
这是典型“领域服务函数”设计,降低对象方法复杂度。
6. 设计评价
优点:
- 模型边界清晰,复杂行为可组合;
- 生命周期可扩展,生态 hook 统一;
- 动态字段与数组场景鲁棒。
成本:
- 需要理解 path/address/display/pattern 等概念;
- 错误定位常常需要跨模型层和 UI 层同时排查。