首页/新闻资讯/正文详情

formily-react ObjectField 组件完全指南:动态对象表单的 ViewModel 桥接与属性增删实战

发布时间:2026/9/24 18:50:35 来源:云帆数科 栏目:资讯中心
formily-react ObjectField 组件完全指南:动态对象表单的 ViewModel 桥接与属性增删实战
前端UI组件【免费下载链接】formily Cross Device High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3项目地址https://gitcode.com/gh_mirrors/fo/formily点击查看免费下载ObjectField 是 formily/react 中用于将 formily/core 的 createObjectField 字段模型ViewModel与输入控件做绑定的桥接组件专治对象值动态增删属性这类复杂表单场景。读完本文你将掌握 ObjectField 的签名与核心属性、两种子组件组织方式自定义组件与 render props以及基于addProperty/removeProperty/existProperty实现动态键值编辑器如自定义 JSON 对象属性面板的完整实战方案。组件定位为什么需要 ObjectField在 formily 的字段体系中字段模型分为普通字段Field、对象字段ObjectField、数组字段ArrayField与虚字段VoidField等类型。ObjectField 对应值类型为对象的字段它的value是一个Recordstring, any因此天然适合表达一组由用户动态决定键名的属性集合例如环境变量配置、自定义扩展属性、KV 映射表等。从源码结构看ObjectField 是 formily/core 的ObjectField字段模型在 React 层的封装其实现位于 packages/react/src/components/ObjectField.tsxexport const ObjectField D extends JSXComponent, C extends JSXComponent( props: IFieldPropsD, C, ObjectFieldType ) { const form useForm() const parent useField() const field useAttach( form.createObjectField({ basePath: parent?.address, ...props }) ) return ( FieldContext.Provider value{field} ReactiveField field{field}{props.children}/ReactiveField /FieldContext.Provider ) }这段实现清晰展示了桥接链路useForm()获取当前FormProvider提供的表单实例useField()获取父级字段用于推导basePath通过form.createObjectField({ basePath: parent?.address, ...props })创建或复用对象字段模型并将其挂载到表单字段图上将字段模型放入FieldContext.Provider供内部嵌套的Field通过useField读取用 ReactiveField 包裹渲染保证字段状态变化时响应式更新 UI。在 formily/core 中createObjectField会保证对象字段的默认值为{}而非undefined相关逻辑见 packages/core/src/models/Form.tscreateObjectField Decorator, Component(props: IFieldFactoryProps...) { const address FormPath.parse(props.basePath).concat(props.name) const identifier address.toString() if (!identifier) return if (!this.fields[identifier] || this.props.designable) { batch(() { new ObjectField(address, { ...props, value: isObj(props.value) ? props.value : {}, }, this, this.props.designable) }) this.notify(LifeCycleTypes.ON_FORM_GRAPH_CHANGE) } return this.fields[identifier] }注意isObj(props.value) ? props.value : {}这一兜底逻辑即使不传value字段值也会被规范化为对象这正是后续Object.keys(field.value || {})遍历安全的前提。签名与核心属性type ObjectField React.FCReact.PropsWithChildrenIFieldFactoryPropsObjectField 的 Props 继承自IFieldFactoryProps定义于 packages/core/src/types.tsexport interface IFieldFactoryProps Decorator extends JSXComponent, Component extends JSXComponent, TextType any, ValueType any extends IFieldPropsDecorator, Component, TextType, ValueType { name: FormPathPattern // 必填字段路径决定字段在表单值树中的位置 basePath?: FormPathPattern // 可选基准路径默认取父级字段地址 }在此基础上React 层的 IFieldProps 补充了三个渲染相关属性属性类型说明nameFormPathPattern必填字段在表单值中的路径如object、a.bbasePathFormPathPattern可选字段的基准路径默认自动取父级字段地址childrenRenderPropsChildrenField可传普通 ReactNode也可传(field, form) ReactNode函数render propsdecorator[] \| [D] \| [D, props]装饰器组件及其属性如 FormItemcomponent[] \| [C] \| [C, props]输入组件及其属性如 Input也可不传、纯靠 children 组织 UI使用警示使用 ObjectField 时必须传name属性同时推荐用 render props 形式组织子组件这样能直接拿到字段模型做动态控制这也是下文两个用例的共同基础。自定义组件用例用 observer 订阅字段模型第一种组织方式是自定义组件 useField。自定义组件通过observer包裹后即可像订阅普通响应式数据一样订阅字段模型的状态变化。完整用例来自 ObjectField.zh-CN.mdimport React from react import { createForm, ObjectField as ObjectFieldType } from formily/core import { FormProvider, Field, ObjectField, useField, observer, } from formily/react import { Input, Button, Space } from antd const form createForm() const ObjectComponent observer(() { const field useFieldObjectFieldType() return ( div {Object.keys(field.value || {}).map((key) ( div key{key} style{{ display: flex-block, marginBottom: 10 }} Space Field name{key} component{[Input, { placeholder: key }]} / Button onClick{() { field.removeProperty(key) }} Remove /Button /Space /div ))} /div Space Field namepropertyName basePath{} required component{[Input, { placeholder: Property Name }]} / Button onClick{() { const name form.values.propertyName if (name !form.existValuesIn(${field.path}.${name})) { field.addProperty(name, ) form.deleteValuesIn(propertyName) } }} Add /Button /Space / ) }) export default () ( FormProvider form{form} ObjectField nameobject component{[ObjectComponent]} / /FormProvider )用例解读useFieldObjectFieldType()在FieldContext内读取当前对象字段模型类型标注为 core 层的ObjectField从而获得addProperty等扩展方法的类型提示渲染已有属性Object.keys(field.value || {})遍历对象键为每个键内嵌一个普通Fieldname{key}相对于当前对象字段路径并配一个 Remove 按钮动态添加属性表单里放一个临时输入框propertyName注意basePath{}使其脱离对象字段路径、挂在表单顶层点击 Add 时读取form.values.propertyName用field.addProperty(name, )写入新属性再用form.deleteValuesIn(propertyName)清空临时输入去重校验form.existValuesIn(${field.path}.${name})用于判断目标路径是否已存在值避免重复添加同名属性observerObjectComponent必须用observer包裹否则新增/删除属性导致field.value变化时组件不会重新渲染。Render Props 用例不写自定义组件也能动态控制如果不想额外定义组件可以直接把 children 写成函数函数参数即字段模型field。此时无需observer、useField因为 render props 本身就是把字段模型作为渲染数据直接传入。完整用例import React from react import { createForm } from formily/core import { FormProvider, Field, ObjectField } from formily/react import { Input, Button, Space } from antd const form createForm() export default () ( FormProvider form{form} ObjectField nameobject {(field) { return ( div {Object.keys(field.value || {}).map((key) ( div key{key} style{{ display: flex-block, marginBottom: 10 }} Space Field name{key} component{[Input, { placeholder: key }]} / Button onClick{() { field.removeProperty(key) }} Remove /Button /Space /div ))} /div Space Field namepropertyName basePath{} required component{[Input, { placeholder: Property Name }]} / Button onClick{() { const name form.values.propertyName if (name !form.existValuesIn(${field.path}.${name})) { field.addProperty(name, ) form.deleteValuesIn(propertyName) } }} Add /Button /Space / ) }} /ObjectField /FormProvider )与自定义组件方案的取舍两种方案的核心逻辑遍历、增删属性完全一致区别在于组织方式自定义组件方案适合属性面板逻辑复杂、需要复用的场景。组件独立成函数配合observer获得响应式订阅后续可抽成通用组件Render Props 方案适合简单、一次性的动态对象编辑内联书写、无需额外组件定义代码更紧凑。从 ReactiveField 的实现看两种方式最终汇合到同一条渲染路径const renderChildren (children, field?, form?) isFn(children) ? children(field, form) : childrenReactiveField会检测 children 是否为函数若是函数则以(field, form)为参数调用render props 分支否则直接作为普通节点渲染自定义组件分支。两种分支共享后续的decorator、component、display非visible不渲染、patterndisabled/readOnly 映射等统一渲染逻辑。源码深处addProperty 与 removeProperty 的实现原理用例中反复使用的三个方法定义在 core 层的字段模型 packages/core/src/models/ObjectField.tsaddProperty (key: string, value: any) { this.form.setValuesIn(this.path.concat(key), value) this.additionalProperties.push(key) return this.onInput(this.value) } removeProperty (key: string) { this.form.deleteValuesIn(this.path.concat(key)) this.additionalProperties.splice(this.additionalProperties.indexOf(key), 1) return this.onInput(this.value) } existProperty (key: string) { return this.form.existValuesIn(this.path.concat(key)) }三个方法的语义与 core 层 ObjectField 模型文档 一致方法签名行为addProperty(key: FormPathPattern, value: any) Promisevoid向对象写入属性setValuesIn并触发onInputremoveProperty(key: FormPathPattern) Promisevoid删除对象属性deleteValuesIn并触发onInputexistProperty(key: FormPathPattern) boolean判断对象中是否存在指定属性值得关注的是模型构造阶段的自动清理机制ObjectField.tsprotected makeAutoCleanable() { this.disposers.push( reaction( () Object.keys(this.value || {}), (newKeys) { const filterKeys this.additionalProperties.filter( (key) !newKeys.includes(key) ) cleanupObjectChildren(this, filterKeys) } ) ) }该模型通过reaction监听对象键集合的变化当某个通过addProperty动态添加的属性键从值中消失被删除时会同步清理该键对应的子字段模型防止字段图Form Graph中残留孤立字段导致状态不同步。这意味着通过addProperty/removeProperty增删属性时子字段会被正确创建/销毁直接通过form.setValuesIn/form.deleteValuesIn修改值也能触发同样的清理逻辑保证字段图与值保持一致。使用注意事项与最佳实践name必须传ObjectField 的name是必填项类型层面强制name: FormPathPattern缺失时字段地址无法解析、字段无法挂载到表单优先 render props 组织子组件把字段模型作为 children 函数的入参能在声明式 JSX 中直接调用addProperty等方法避免额外编写observer组件区分对象字段与普通字段若值结构固定如一个已知 schema 的对象用Field JSON Schema 即可只有当键名需要运行时动态增删时才需要 ObjectField其价值在于addProperty/removeProperty对子字段图的自动维护临时输入框用basePath{}隔离动态添加属性时需要一个属性名输入框将其basePath设为空串可避免它被错误地嵌套进对象字段的值路径配合响应式渲染若采用自定义组件方案务必用observer包裹render props 方案则由 ReactiveField 内置的响应式机制保证更新无需手动处理。小结ObjectField 是 formily 对象类型字段在 React 层的标准桥接组件它把 core 层的对象字段模型通过FieldContext注入到子组件树并借助ReactiveField完成响应式渲染。配合addProperty/removeProperty/existProperty三个扩展方法与自动清理机制可以高效实现属性动态增删的复杂编辑场景。本文的两个完整用例自定义组件 render props均可直接复制运行适合作为自定义 KV 编辑器、动态扩展属性面板等功能的基础模板。赞分享前端UI组件【免费下载链接】formily Cross Device High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3项目地址https://gitcode.com/gh_mirrors/fo/formily点击查看免费下载相关推荐Formily Vue ObjectField 组件全解析动态对象结构表单的 ViewModel 桥接实践Formily Vue ObjectField 组件全解析动态对象结构表单的 ViewModel 桥接实践 ObjectField 是 Formily Vue前端UI组件Formily Core ObjectField 模型完全指南对象字段的动态属性增删与状态管理Formily Core ObjectField 模型完全指南对象字段的动态属性增删与状态管理 ObjectField 是 Formily 核心模型体系中专门前端UI组件Formily React ArrayField 组件完全指南数组型字段的 ViewModel 绑定与增删改排实战Formily React ArrayField 组件完全指南数组型字段的 ViewModel 绑定与增删改排实战 ArrayField 是 Formily前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

iOS开发工具选型指南:Xcode、AppCode等五款工具对比与实战
iOS开发工具选型指南:Xcode、AppCode等五款工具对比与实战

1. iOS开发工具选型的底层逻辑 1.1 为什么工具选择会直接影响开发效率 干了十来年iOS,我越来越觉得,工具选型这件事被很多新手严重低估了。大多数人刚入门的时候,脑子里只有一个概念——写iOS就得用Xcode,其他都是花里胡哨。但实… · 2026/9/24 18:50:35

200张真实田间YOLO作物杂草数据集(v5-v11全兼容)
200张真实田间YOLO作物杂草数据集(v5-v11全兼容)

简介:本资源是面向农业AI与计算机视觉初学者的YOLO系列目标检测实战数据集,专为作物与杂草识别任务设计,适用于YOLOv5至YOLOv11等主流版本模型的训练、验证与测试。数据集包含200张高质量农田场景图像(JPG)&#xff0c… · 2026/9/24 18:50:35

5G NR里DMRS到底怎么用?一文拆解时频结构、参数配置与性能影响
5G NR里DMRS到底怎么用?一文拆解时频结构、参数配置与性能影响

1. 5G NR里DMRS到底是什么,搞懂它才算入了物理层的门做5G协议栈或者物理层算法的人,几乎每天都要和DMRS打交道。不管是刚入行的应届生,还是从4G转过来的老工程师,第一次看38.211的时候基本都会被DMRS的时频结构绕晕。但说实话&… · 2026/9/24 18:50:35

AI生成PPT工具实测:七款工具场景定位与高效工作流
AI生成PPT工具实测:七款工具场景定位与高效工作流

做演示文稿这件事,最耗时间的往往不是排版美化,而是从一堆散乱资料里理出结构、再把结构翻译成一页页能看的幻灯片。我过去几年帮团队做过不少技术分享、项目汇报和方案评审,前前后后试过十几款号称能"一键生成PPT"的工具&#xff… · 2026/9/24 20:47:53

接触效率与实际电荷密度:电化学测试的关键参数
接触效率与实际电荷密度:电化学测试的关键参数

入行电化学测试这些年,在电容材料和器件这一块被问得最多的问题,不是“比电容多少”,而是“电容的接触效率和实际电荷密度怎么测”。说实话,能问出这两个词的,多半是已经被标称数据坑过的。样品在实验室里用压片机压出… · 2026/9/24 20:47:53

AI驱动金融投研工作流:从信息处理到决策辅助的实操指南
AI驱动金融投研工作流:从信息处理到决策辅助的实操指南

1. 金融投研的底层逻辑正在被重写干了十多年投研,我经历过从Excel手工拉数据到Wind终端批量导出的全过程。早年间写一份行业深度报告,光是整理财报数据、做可比公司估值表就得耗掉两三天,剩下的时间才敢谈“分析”。现在情况完全变了——大模… · 2026/9/24 20:47:53

JMeter高效构造MySQL测试数据:性能测试数据准备实战指南
JMeter高效构造MySQL测试数据:性能测试数据准备实战指南

1. 为什么要费劲用 JMeter 给 MySQL 构造测试数据1.1 测试数据不足这件事,到底有多拖后腿做性能测试的人应该都有体会:真正开始压接口之前,最浪费时间的事情往往不是写脚本,而是搞定测试数据。接口压测需要一批符合业务规则的存量… · 2026/9/24 20:47:53

5G基站BBU深度拆解:从基带单元到CU/DU架构的硬核指南
5G基站BBU深度拆解:从基带单元到CU/DU架构的硬核指南

1. 拆解BBU:5G基站里那个不显眼却最烧脑的盒子 很多人第一次听到BBU这个词,脑子里浮现的是某个潮牌或者电池品牌。但在通信行业里,BBU(Baseband Unit,基带单元)是5G基站里真正负责“动脑子”的那个部件。你… · 2026/9/24 20:47:39

使用 @openuidev/devtools 调试 OpenUI 应用:Inspect 事件面板与 Debug 工作台实战指南
使用 @openuidev/devtools 调试 OpenUI 应用:Inspect 事件面板与 Debug 工作台实战指南

使用 openuidev/devtools 调试 OpenUI 应用:Inspect 事件面板与 Debug 工作台实战指南 【免费下载链接】openui The Open Standard for Generative UI 项目地址: https://gitcode.com/gh_mirrors/openui1/openui openuidev/devtools 是 OpenUI 生态中的开发期… · 2026/9/24 20:47:39

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码