`getFieldDecorator` will override `value`, so please don't set `value` ...处理

275 阅读2分钟

需求中会遇到ant-design的Form表单动态添加和删除FormItem项,每个添加的FormItem还能单独校验,比如下面可以添加和删除多个输入框,每个都可以单独校验:

image.png

为了校验格式保持一致,这时会想着动态去更改数据来控制FormItem的添加和删除,但这时会涉及数据的直接更改,造成Form表单会报以下的错:

Warning: getFieldDecorator will override value, so please don't set value directly and use setFieldsValue to 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表单中的值,而是直接修改源数据即可,这样操作方便,代码也比较清晰。