antd form表单如何处理自定义组件

 更新时间:2023年04月21日 10:58:36   作者:丶酸酸  
这篇文章主要介绍了antd form表单如何处理自定义组件问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

antd form表单处理自定义组件

使用 antd 中的 Form 组件时,若使用自定义组件时,保存的时候获取不到自定义组件中的值。

以下是从antd找到的解决思路

被设置了 name 属性的 Form.Item 包装的控件,表单控件会自动添加 value(或 valuePropName 指定的其他属性) onChange(或 trigger 指定的其他属性)

我们可以通过表单控件自动添加的onChage,来做数据收集同步。

父组件:

import React, { Fragment, useState, useEffect, forwardRef, useRef } from 'react';
import HeaderTable from './headerTable';

const BasicForm = forwardRef((props, ref) => {
  const { record } = props;
  const [ form ] = Form.useForm();

    <Form
          name="taskForm"
          ref={ref}
          form={form}
        >
        <Row gutter={20}>
            <Col span={24}>
              <Form.Item  name="headers" label={'Header'}>
                <HeaderTable ref={headerTableRef} record={record} />
              </Form.Item>
            </Col>
          </Row>
    </Form>
export default BasicForm;

子组件:

import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef} from 'react';
import { Transfer, Divider, Table, Button, Input, message, Select } from 'antd';
import AddRowTable from '@components/AddRowTable';//Table组件

const { Option } = Select;

const DATATYPE = [
    {
        id: 1,
        name: 'int'
    }, {
        id: 2,
        name: 'varchar'
    }
]

const HeaderTable = ( props, ref ) => {
    const { record, isLook, onChange } = props;
    const addRowTable = useRef();
    const [ sourceData, setSourceData ] = useState([]);
    const [ columns, setColumns ] = useState([]);
    const [ targetKeys, setTargetKeys ] = useState([]);
    const [ headerList, setHeaderList ] = useState([]);

    useEffect(() => {
        if (record && record.id) {//当编辑时将传来的数据赋值
            setHeaderList(record.sourceInfoMap.headers)
        }
    }, [record])
        
        //设置columns表头
        useEffect(() => {
        const columns = [
    {
            title: '参数名称',
            dataIndex: 'name',
            render: (text, record) => {
        return (
            <Input value={text} onChange={tableItemChange.bind(this, record, 'name')} />
            );
        }
    },
        {
            title: '操作',
            dataIndex: 'operation',
            align: 'center',
            render: (text, record, index) => {
        return (
                    <a onClick={delHandle.bind(this, record, index)}>'Delete'</a>
                        );
        }
    }];
        
        setColumns(columns);
        
        },[])

    // 添加一行
    const handleAddTableRow = () => {
        setHeaderList(headerList => [...headerList, {}]);
        onChange(headerList => [...headerList, {}])
    };


    // 删除一行
    const delHandle = (record, index) => {
        setHeaderList(headerList => {
            headerList.splice(index, 1);
            onChange(headerList)
            return [...headerList];
        });
    };

    // 表格中数据更改
    const tableItemChange = (data, keyField, evt) => {
        const value = evt.target ? evt.target.value : evt;
        data[keyField] = value;
        onChange(headerList)
    };

    return <div>
        <AddRowTable
            ref={addRowTable}
            dataSource={headerList}
            columns={columns}
            isCanAdd={isLook}
      disabled={isLook}
            addItem={handleAddTableRow.bind(this)}
        />
    </div>
}

export default HeaderTable;

以上操作就可以在表单中使用自定义组件,表单也能统一获取值。

不仅仅input输入框可以这么操作,所有组件,只要你拿到值后,把值给 onChange 方法,都是可以统一获取值的。

antd form表单中嵌套自定义组件

当某些自定义的组合类组件,也希望能进行表单元素的校验,以及利用antd的form表单实例进行数据的修改或者数据获取,这招便可以派上用场啦~

表单部分

<Form.Item label="周期" labelAlign="right">
    {getFieldDecorator('cycle', {
        rules: [{ required: true, validator: checkCycle }],
        initialValue: cycle,
    })(<CycleInput cycleOptions={cycleOptions} />)}
</Form.Item>

表单部分可以引入自定义的校验逻辑,如上面的checkCycle :

可以像下面这样,通过Promise.reject()返回错误校验提示,通过Promise.resolve()正确通过校验。

/** 校验生命周期输入内容 */
const checkCycle = useCallback((_, value) => {
     const format = value?.split(' ');
     if (!format) return Promise.reject(new Error('周期不可为空!'));

     /** always 永久保存选项 */
     if (format.length < 2 && format[0] === 'always') {
         return Promise.resolve();
     }
     if (format[1] === 'undefined') {
         return Promise.reject(new Error('请选择周期!'));
     }
     const num = +format[0];
     if (num > 0 && format[1]) {
         return Promise.resolve();
     }
     return Promise.reject(new Error('请输入大于 0 的数字!'));
 }, []);

有关校验的内容,antd也是参考一个成熟的库 async-validator,上面这种写法可以参考文档这块 asyncValidator

如果懒得看文档直接看图:

asyncValidator的用法

大概意思就是说,可以通过两种方式来实现一些异步校验:

(1)可以通过调用callback,即asyncValidator的第三个参数,来完成校验

(2)可以通过返回Promise,来完成校验

自定义组件

注意value是该表单域的值,onChange是对应可以改变该表单域的值的方法

const CycleInput = ({ value, onChange, cycleOptions }) => {
    const format = value?.split?.(' ');
    const num = format?.[0];
    const type = format?.[1];

    const triggerChange = changedValue => {
        onChange && onChange(changedValue);
    };

    /** 根据后端接口返回的数据,type 有值,则为 day、week、month、year 其一 */
    /** type 若为 undefined,则 num 为 always */
    const [cycleOption, setCycleOption] = useState(type ?? num);
    const [cycleInputValue, setCycleInputValue] = useState(
        (typeof +num === 'number' && !_.isNaN(+num) && num) || '',
    );

    const onCycleChange = cycleOption => {
        setCycleOption(cycleOption);
        triggerChange(
            cycleOption === 'always'
                ? cycleOption
                : `${cycleInputValue} ${cycleOption}`,
        );
    };

    const onInputChange = e => {
        const newNumber = parseInt(e.target.value || '0', 10);
        if (_.isNaN(newNumber)) {
            return;
        }
        setCycleInputValue(newNumber);
        triggerChange(
            cycleOption === 'always' ? cycleOption : `${newNumber} ${cycleOption}`,
        );
    };

    return (
        <Input.Group>
            {cycleOption === 'always' ? (
                <Select
                    onChange={onCycleChange }
                    defaultValue={cycleOption}
                    style={{ width: 240 }}
                >
                    {cycleOptions.map(item => (
                        <Select.Option key={item.value} value={item.value}>
                            {item.label}
                        </Select.Option>
                    ))}
                </Select>
            ) : (
                <span>
                    <Input
                        value={cycleInputValue}
                        style={{ width: 156 }}
                        onChange={onInputChange}
                    />
                    <Select
                        onChange={onCycleChange}
                        defaultValue={cycleOption}
                        style={{ width: 84 }}
                    >
                        {cycleOptions.map(item => (
                            <Select.Option key={item.value} value={item.value}>
                                {item.label}
                            </Select.Option>
                        ))}
                    </Select>
                </span>
            )}
        </Input.Group>
    );
};

可以看出,自定义部分逻辑也比较简单,通过value参数可以展示组件的值,通过onChange方法,可以改变表单域的值,实现了表单带给我们的便捷功能。

总结

到此结束啦,快试试吧,实践出真知呀!

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • React点击事件的两种写法小结

    React点击事件的两种写法小结

    这篇文章主要介绍了React点击事件的两种写法小结,具有很好的参考价值,希望对大家有所帮助。
    2022-12-12
  • 详解React native全局变量的使用(跨组件的通信)

    详解React native全局变量的使用(跨组件的通信)

    本篇文章主要介绍了详解React native全局变量的使用(跨组件的通信),具有一定的参考价值,有兴趣的同学可以了解一下
    2017-09-09
  • React 实现表单组件的示例代码

    React 实现表单组件的示例代码

    本文主要介绍了React 实现表单组件的示例代码,支持包括输入状态管理,表单验证,错误信息展示,表单提交,动态表单元素等功能,具有一定的参考价值,感兴趣的可以了解一下
    2024-07-07
  • Yarn安装项目依赖报error An unexpected error occurred: “XXXXX:ESOCKETTIMEOUT”问题解决

    Yarn安装项目依赖报error An unexpected error occurred: “XXXXX:E

    这篇文章主要为大家介绍了Yarn安装项目依赖报error An unexpected error occurred: “XXXXX:ESOCKETTIMEOUT”问题解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • 40行代码把Vue3的响应式集成进React做状态管理

    40行代码把Vue3的响应式集成进React做状态管理

    这篇文章主要介绍了40行代码把Vue3的响应式集成进React做状态管理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • React实现导入导出Excel文件

    React实现导入导出Excel文件

    本文主要介绍了React实现导入导出Excel文件,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • React利用插件和不用插件实现双向绑定的方法详解

    React利用插件和不用插件实现双向绑定的方法详解

    我们知道在 angular 中数据时双向绑定的;而在 react 中,数据是向一个方向传递:从拥有者到子节点。也就是我们说的单向数据绑定。那如何实现双向绑定呢?下面这篇文章主要给大家介绍了关于React利用插件和不用插件实现双向绑定的方法,需要的朋友可以参考下。
    2017-07-07
  • react实现原生下拉刷新

    react实现原生下拉刷新

    这篇文章主要为大家详细介绍了react实现原生下拉刷新,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • 浅谈React中组件逻辑复用的那些事儿

    浅谈React中组件逻辑复用的那些事儿

    这篇文章主要介绍了浅谈React中组件逻辑复用的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • react组件实例属性state详解

    react组件实例属性state详解

    这篇文章主要介绍了react组件实例属性state,有状态state的组件称作复杂组件,没有状态的组件称为简单组件,状态里存储数据,数据的改变驱动页面的展示,本文结合实例代码给大家详细讲解,需要的朋友可以参考下
    2023-02-02

最新评论