Antd Form setFieldsValue失败原因

4,577 阅读2分钟

烦恼和焦虑大都来源于无知。共勉!

记录一下setFieldsValue失败的血泪史,使用Antd的应该都会经常使用Form表单吧,编辑表单的时候经常需要回填默认值,这里有3个API可以使用,setFields, setFieldValuesetFieldsValue

在线代码演示: stackblitz.com/edit/react-…

import React, { useEffect } from 'react';
import { Form, Input, Table, Button } from 'antd';
import { dataSource, detailResponse } from './formDemoData';

export default () => {
  const [form] = Form.useForm();

  const columns1 = [
    {
      title: '姓名',
      dataIndex: 'name',
      key: 'name',
    },
    {
      title: '年龄',
      dataIndex: 'age',
      key: 'age',
    },
    {
      title: 'value',
      dataIndex: 'value',
      key: 'value',
      render: (text, record, index) => {
        return (
          <>
            <Form.Item noStyle name={['b', index, 'value']}>
              <Input />
            </Form.Item>
          </>
        );
      },
    },
  ];

  const columns2 = [
    {
      title: '姓名',
      dataIndex: 'name',
      key: 'name',
    },
    {
      title: '年龄',
      dataIndex: 'age',
      key: 'age',
    },
    {
      title: 'value',
      dataIndex: 'value',
      key: 'value',
      render: (text, record, index) => {
        return (
          <>
            <Form.Item noStyle name={['c', 'b', index, 'value']}>
              <Input />
            </Form.Item>
          </>
        );
      },
    },
  ];

  const columns3 = [
    {
      title: '姓名',
      dataIndex: 'name',
      key: 'name',
    },
    {
      title: '年龄',
      dataIndex: 'age',
      key: 'age',
    },
    {
      title: 'value',
      dataIndex: 'value',
      key: 'value',
      render: (text, record, index) => {
        return (
          <>
            <Form.Item noStyle name={['c', 'c1', 'b', index, 'value']}>
              <Input />
            </Form.Item>
          </>
        );
      },
    },
  ];

  useEffect(() => {
    setTimeout(() => {
      form.setFieldsValue(detailResponse);

      // form.setFieldValue('a', detailResponse.a);
      // form.setFieldValue('b', detailResponse.b);
      // form.setFieldValue(['c', 'b'], detailResponse.c.b);
      // form.setFieldValue(['c', 'c1', 'b'], detailResponse.c.c1.b);
      // form.setFieldValue(['c', 'c1', 'c2'], detailResponse.c.c1.c2);

      // form.setFields([
      //   { name: 'a', value: detailResponse.a},
      //   { name: 'b', value: detailResponse.b},
      //   { name: ['c', 'b'], value: detailResponse.c.b},
      //   { name: ['c', 'c1', 'b'], value: detailResponse.c.c1.b},
      //   { name: ['c', 'c1', 'c2'], value: detailResponse.c.c1.c2}
      // ])
    }, 1000);
  }, []);

  const onFinish = (values) => {
    console.log(values);
  };

  return (
    <div>
      <h3>antd Form复杂表单</h3>
      <Form form={form} onFinish={onFinish}>
        <Form.Item label="一级字段a" name="a">
          <Input />
        </Form.Item>

        <Form.Item label="一级字段是数组b" name="b">
          <Table
            columns={columns1}
            dataSource={dataSource}
            pagination={false}
          />
        </Form.Item>

        <Form.Item label="二级是数组【c.b】" name={['c', 'b']}>
          <Table
            columns={columns2}
            dataSource={dataSource}
            pagination={false}
          />
        </Form.Item>

        <Form.Item label="三级是数组【c.c1.b】" name={['c', 'c1', 'b']}>
          <Table
            columns={columns3}
            dataSource={dataSource}
            pagination={false}
          />
        </Form.Item>

        <Form.Item label="三级字段c.c1.c2" name={['c', 'c1', 'c2']}>
          <Input />
        </Form.Item>

        <Button type="primary" htmlType="submit">
          提交
        </Button>
      </Form>
    </div>
  );
};

// formDemoData.js
const bList = [
  { id: 1, value: 'b1' },
  { id: 2, value: 'b2' },
];

export const detailResponse = {
  a: 'a',
  b: bList,
  c: {
    b: bList,
    c1: {
      c2: 'c2',
      b: bList,
    },
  },
};

export const dataSource = [
  {
    key: '1',
    id: 1,
    name: '胡彦斌',
    age: 32,
  },
  {
    key: '2',
    id: 2,
    name: '吴彦祖',
    age: 32,
  },
];

到这里大家应该发现了,嗯?这一切都很正常,为什么开头要说血泪史呢? 这是因为demo,demo就是demo,数据提交和返回值都是自己定义好的,不会有什么问题,但做项目的时候,字段名可能很长,笔者就是认为就是Form.setFilesValue能有什么问题,但默认值就是显示不出来,数据格式就是 data.a.b 是个数组,怎么就有问题了呢?

百度了好久,甚至在github上找到了issue,说setFieldsValue没有考虑namePath的情况 github.com/react-compo…

之前也没有发现setFieldsValue不支持嵌套啊,写了这么多年代码,着实给我整懵了!

一番折腾后,在晚上十点钟,终于找到了我想要的答案,原来是返回的字段名和提交的字段名不一致导致的,捶胸顿足啊!!!

之前也不是没发现提交和返回的字段不一致,只是没发现嵌套的二级字段也不一样,这样的话就需要小心了。

    // 提交字段
    const params = {
        // ...
        activityFinalAccountsDTO: {
            // ...
            branchOfficeFinalAccountsDTOList: [{}]
        }
    }
    
    // 返回值字段
    const response = {
        // ...
        activityFinalAccountsInfo: {
            // ...
            branchOfficeFinalAccountsInfos: [{}]
        }
    }
    
    // bugfix: setFilesValue 前统一字段名
    activityFinalAccountsInfo.branchOfficeFinalAccountsDTOList = activityFinalAccountsInfo.branchOfficeFinalAccountsInfos
    
    form.setFieldsValue({
         // ...
         activityFinalAccountsDTO: activityFinalAccountsInfo
    })
    
    

总结:复杂表单提交和有默认值的情况下,一定要注意前后字段名是否一致,尤其是有嵌套的字段名是否一致,不一致的时候,要在 setFilesValue 前统一字段名。