logoAnt Design

⌘ K
  • 디자인
  • 개발
  • 컴포넌트
  • 블로그
  • 자료
5.21.3
  • 为什么禁用日期这么难?
  • Why is it so hard to disable the date?
  • 封装 Form.Item 实现数组转对象
  • HOC Aggregate FieldItem
  • 行省略计算
  • Line Ellipsis Calculation
  • 📢 v4 维护周期截止
  • 📢 v4 surpassed maintenance period
  • Type Util
  • 一个构建的幽灵
  • A build ghost
  • 当 Ant Design 遇上 CSS 变量
  • Ant Design meets CSS Variables
  • API 기술 부채
  • 생동감 있는 Notification
  • 色彩模型与颜色选择器
  • Color Models and Color Picker
  • 主题拓展
  • Extends Theme
  • 虚拟表格来了!
  • Virtual Table is here!
  • Happy Work 테마
  • Happy Work Theme
  • 동적 스타일은 어디로 갔을까?
  • Suspense 引发的样式丢失问题
  • Suspense breaks styles
  • Bundle Size Optimization
  • 안녕, GitHub Actions
  • 所见即所得
  • To be what you see
  • 정적 메서드의 고통
  • SSR에서 정적 스타일 추출
  • SSR Static style export
  • 의존성 문제 해결
  • 贡献者开发维护指南
  • Contributor development maintenance guide
  • 转载-如何提交无法解答的问题
  • Repost: How to submit a riddle
  • 新的 Tooltip 对齐方式
  • Tooltip align update
  • Unnecessary Rerender
  • 如何成长为 Collaborator
  • How to Grow as a Collaborator
  • Funny Modal hook BUG
  • Modal hook 的有趣 BUG
  • about antd test library migration
  • antd 测试库迁移的那些事儿
  • Tree 的勾选传导
  • Tree's check conduction
  • getContainer 的一些变化
  • Some change on getContainer
  • Component-level CSS-in-JS

封装 Form.Item 实现数组转对象

Resources

Ant Design Charts
Ant Design Pro
Ant Design Pro Components
Ant Design Mobile
Ant Design Mini
Ant Design Landing-Landing Templates
Scaffolds-Scaffold Market
Umi-React Application Framework
dumi-Component doc generator
qiankun-Micro-Frontends Framework
ahooks-React Hooks Library
Ant Motion-Motion Solution
China Mirror 🇨🇳

Community

Awesome Ant Design
Medium
Twitter
yuque logoAnt Design in YuQue
Ant Design in Zhihu
Experience Cloud Blog
seeconf logoSEE Conf-Experience Tech Conference
Work with Us

Help

GitHub
Change Log
FAQ
Bug Report
Issues
Discussions
StackOverflow
SegmentFault

Ant XTech logoMore Products

yuque logoYuQue-Document Collaboration Platform
AntV logoAntV-Data Visualization
Egg logoEgg-Enterprise Node.js Framework
Kitchen logoKitchen-Sketch Toolkit
Galacean logoGalacean-Interactive Graphics Solution
xtech logoAnt Financial Experience Tech
Theme Editor
Made with ❤ by
Ant Group and Ant Design Community
loading

在表单开发过程中,偶尔会遇到组合属性的需求。UI 展示字段与后端返回数据结构字段有所不同。比如说,跟后端对接接口,定义省市字段经常是 2 个字段 { province: Beijing, city: Haidian },而不是 { province:[Beijing,Haidian] },因此则需要在 initialValues 以及 onFinish 处理值,如下:

import React from 'react';
import { Cascader, Form } from 'antd';
const data = { province: 'Beijing', city: 'Haidian' };
const options = [
{ value: 'zhejiang', label: 'Zhejiang', children: [{ value: 'hangzhou', label: 'Hangzhou' }] },
{ value: 'jiangsu', label: 'Jiangsu', children: [{ value: 'nanjing', label: 'Nanjing' }] },
];
const createUser = (values) => console.log(values);
const Demo = () => (
<Form
initialValues={{ province: [data.province, data.city] }}
onFinish={(values) => {
const { province, ...rest } = values;
createUser({ province: province[0], city: province[1], ...rest });
}}
>
<Form.Item label="Address" name="province">
<Cascader options={options} placeholder="Please select" />
</Form.Item>
</Form>
);
export default Demo;

封装聚合字段组件

当表单比较简单还好,如果遇到 Form.List 场景,就需要 map 处理值,将变的很复杂。于是我们需要封装聚合字段组件,实现一个 Form.Item 可以写多个 name。

思路整理

要实现聚合字段功能,我们需要用到 getValueProps getValueFromEvent transform,从而实现数据从 FormStore 中的转化,以及变更时重新传入 FormStore 结构中。

getValueProps

默认情况下,Form.Item 会将 FormStore 中的字段值作为 value prop 传递给子组件。而通过 getValueProps 可以自定义传入给子组件的 props 从而实现转化功能。在聚合场景中,我们可以遍历 names 分别将 FormStore 中的值组合为一个 value 传递给子组件:

getValueProps={() => ({ value: names.map((name) => form.getFieldValue(name)) })}

getValueFromEvent

当子组件修改值时,使用 setFields 方法将子组件返回的聚合 value 分别设置给对应的 name,从而实现更新 FormStore 中 names 的值:

getValueFromEvent={(values) => {
form.setFields(names.map((name, index) => ({ name, value: values[index] })));
return values[0];
}}

transform

rules 中校验默认提供的 value 来源于子组件变更时传递给 name 对应的值,还需要从 FormStore 获取 names 的值使用 transform 方法修改 rules 的 value:

rules={[{
transform: () => {
const values = names.map((name) => form.getFieldValue(name));
return values;
},
}]}

最终效果

总结

通过这种方式,我们实现了一个可以在 Form.Item 中操作多个 name 的功能,使得表单逻辑更加清晰和易于维护。

除了文中的 Cascader 示例,同样适用于 DatePicker.RangePicker 等组件。换句话说,只要是需要聚合多个字段的场景,都可以使用这种方式。

另外此示例还有些边界场景没有考虑,比如 setFields([{ name:'city' value:'nanjing' }]) 不会更新 Cascader 选中的值,需要增加 Form.useWatch(values => resetNames.map(name => get(values, name)), form); 达到刷新效果等。

更多的边界问题就交给你去试试吧~

codepen icon
External Link Icon
expand codeexpand code
Beijing / Haidian
Please select