使用Hooks时使用setFieldsValue设置初始值无效的问题

13,103 阅读2分钟

遇到的问题:我们经常用用 antd 的 form 中的setFieldsValue来给表单设置值,以实现表单的回显;但是有时并不那么顺利,我个人也在写代码或者改别人代码bug中遇到过类似的问题,明明设置成功了,却没有回显。

以下是从发现问题到解决问题的过程

我想在页面开始时就有回显的数据,于是写了下边的代码

  useEffect(() => {
    if (statusId) {
        form.setFieldsValue({flowStatus: 1});
      }
  }, [statusId]);

但是这个select框没有任何变化;---(此时怀疑数据格式问题)

过程1:怀疑数据格式

于是更改了数据格式:

  {flowStatus: 1} 变为 {flowStatus: '1'};

即,将数字转化为字符串,发现仍然不能回显。---(此时怀疑是值没有被赋值上去)

过程2: 怀疑没有赋值

为了验证值有没有被赋值,打印一下看看

   useEffect(() => {
    if (statusId) {
        form.setFieldsValue({flowStatus: 1});
        console.log('flowStatus', form.getFieldValue('flowStatus'))
      }
  }, [statusId]);

可以看到flowStatus 有值但是仍然没有回显;这就奇怪了,命名设置了值,值也拿到了,为什么没有回显;antd出bug了。---(难道antd出bug了?)

过程3: 再度思考--万念俱灰

会不会有其他的api也改变了我赋的值,那么这些api有没有出现。form.resetFields();也会改变这个值,于是去看哪里用到了这个api; 于是我找到了这块代码

  useEffect(() => {
    if (formConfigListValues.length === 0) { // todo  不能用这个判断
      form.resetFields();
      
    }
  }, [formConfigListValues]);

看到这块代码,是这块问题的概率大概有90%; 打印验证一下

结论:果然再赋值之后又被重置,导致了没有回显;

过程4:回显成功,有点瑕疵

找到问题了,所以应该如何写呢。以下是我的代码;

  useEffect(() => {
    if (formConfigListValues.length === 0) {
      form.resetFields();
      if (statusId) {
        form.setFieldsValue({flowStatus: 1});
      }
    }
  }, [formConfigListValues, statusId]);

我的个人思考是

  • 1:resetFields这个api用的次数很少,基本就用一次,不如放在此处的useEffect里边;
  • 2:将setFieldsValue和resetFields放在一块,方便后期的维护,降低其他人修改代码的成本;

但是这种是 错误 的;因为formConfigListValues在每次操作完表单时候要走一遍,但是导致了,审批状态一直不会变(也就是操作审核状态失效); 运行结果:

最后的结果:云开雾散,水落石出,真相大白

最后的代码如下:

  useEffect(() => {
    if (formConfigListValues.length === 0) {
      form.resetFields();
    }
  }, [formConfigListValues]);
  
  useEffect(() => {
      if (statusId) {
        form.setFieldsValue({flowStatus: 1});
      }
  }, [statusId]);

最终思考 当我们在Hooks组件中使用Antd表单form的setFieldsValue,时要有注意,

  • 1: 是否数据格式错误(value应该是字符串还是数字)
  • 2: 在数据格式正确但是没有回显的,要想到还有哪些也可能影响设置值(如:resetFields)
  • 3: 在hooks中使用setFieldsValue,还要注意写代码的顺序和层级结构(如:新加的setFieldsValue到底放在里边还是外边,放到外边的话是否要注意,要放在resetFields所在useEffect的下边)。