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
如果懒得看文档直接看图:
大概意思就是说,可以通过两种方式来实现一些异步校验:
(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方法,可以改变表单域的值,实现了表单带给我们的便捷功能。
总结
到此结束啦,快试试吧,实践出真知呀!
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
Yarn安装项目依赖报error An unexpected error occurred: “XXXXX:E
这篇文章主要为大家介绍了Yarn安装项目依赖报error An unexpected error occurred: “XXXXX:ESOCKETTIMEOUT”问题解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-03-03
最新评论