需求中会遇到ant-design的Form表单动态添加和删除FormItem项,每个添加的FormItem还能单独校验,比如下面可以添加和删除多个输入框,每个都可以单独校验:
为了校验格式保持一致,这时会想着动态去更改数据来控制FormItem的添加和删除,但这时会涉及数据的直接更改,造成Form表单会报以下的错:
Warning:
getFieldDecoratorwill overridevalue, so please don't setvaluedirectly and usesetFieldsValueto set it.
当点击删除时也会出现数据错乱,删除第一个会把第二个删除了,第一个依然存在。
这时可以把input的value和onChange去掉,使用From表单提供的getFieldDecorator和setFieldDecorator来获取和设置值,但这样没有直接更改源数据方便。
所以想通想直接改变源数据来控制数据的展示,可以在FormItem下添加一个空标签来解决这个问题,这是因为:
在 Ant Design Form 中,getFieldDecorator 的工作原理是:
- 它接收一个表单控件作为子元素
- 通过 React.cloneElement 克隆这个子元素
- 为克隆后的元素注入新的 props(包括 value 和 onChange)
使用空标签 <> 时:
- getFieldDecorator 会克隆空标签
- 空标签会保持其子元素(Input)的原始结构
- getFieldDecorator 可以正确地将 value 和 onChange 注入到 Input 组件中
- 由于空标签本身不接收任何 props,所以不会产生属性冲突
示例代码如下:
<FormItem
label="标签名称"
required
>
{
renderTagList?.map((item: any, index: number) => (
<div key={index} className={styles.tagItem}>
<FormItem
label=""
required
>
{
getFieldDecorator(`TagName${index}`, {
rules: [
{
validator: (rule, value, callback) => {
const trimName = renderTagList[index]?.name?.trim();
if (!trimName) {
callback('请填写标签名称');
}
else {
callback();
}
}
}
],
})(
// 空标签,隔断Form表单默认赋值
<>
<div className={styles.tagName}>
<Input
value={item?.name?.trim()}
placeholder="请填写标签名称"
onChange={evt => handleChangeTagName(evt.target.value?.trim(), index)}
/>
<Icon
type="delete"
className={styles['tagName-delete']}
onClick={() => handleDeleteTag(index)}
/>
</div>
</>
)
}
</FormItem>
</div>
))
}
</FormItem>
在FormItem下添加空标签<>包裹元素,这样就不用使用getFieldDecorator和setFieldDecorator来获取和更改Form表单中的值,而是直接修改源数据即可,这样操作方便,代码也比较清晰。