一、前言
今天开发的时候,发现一个页面的表单其实是两个部分,其中一部分还在另一个页面引用了。这就增加代码量,所以优化下,为了重复使用这里的表单。
如图,需求就是将下面两个表单拆开,可以重复使用,实际两部分可能有很多表单,这里方便起见,只写了三个。
二、涉及到知识点
- react hooks
- antd 4.0(Form)
- Promise
- 子父组件传值和父组件调用子组件方法
三、实现方法
具体实现:我放在了Codesandbox,可以直接打开调试
- 1、首先为了充分复用表单组件,那么就要拆分的彻底一点,不能关联太多内容。
- 2、一个模版表单单独作为一个组件,表单通过useForm()创建。
- 3、在组件外部进行表单提交,分别触发,然后通过Promise.all方法获取表单数据。
- 4、编辑的时候,可以通过props将给表单赋值,然后给子组件注册供父组件调用的方法。
四、具体操作
我们通过codesandbox
来试验下,这里表单添加的比较少,可以自行增加。
新建index.js
文件,表单最后显示在这里
两个表单模版:templateForm1.js
templateForm2.js
,由于这两个文件的内容基本一样,需要根据自己的表单内容定义,所以我们这里写了一个。
import React, { useRef } from "react";
import { Button, Divider } from "antd";
import TemplateForm1 from "./templateForm1";
import TemplateForm2 from "./templateForm2";
export default function App() {
const template1Ref = useRef();
const template2Ref = useRef();
const formItemLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 10 }
};
const handleCommit = () => {
let template1Data = new Promise((resolve, reject) => {
template1Ref.current.commitForm((value) => {
resolve(value);
});
});
let template2Data = new Promise((resolve, reject) => {
template2Ref.current.commitForm((value) => {
resolve(value);
});
});
Promise.all([template1Data, template2Data]).then((res) => {
console.log("get", res);
});
};
return (
<div className="App">
<Divider orientation="left">内部信息</Divider>
<TemplateForm1 ref={template1Ref} formItemLayout={formItemLayout} />
<Divider orientation="left">外部信息</Divider>
<TemplateForm2 ref={template2Ref} formItemLayout={formItemLayout} />
<Button onClick={handleCommit}>提交</Button>
</div>
);
}
复制代码
在该文件中,我们引入了两个表单的模版,通过ref属性获取组件,通过props传入父组件的变量。
当我们调用handleCommit
的时候,该函数会调用子组件定义好的commitForm
的方法来获取表单的数据,获取的数据通过回调函数返回。
因为多个组件存在异步获取的问题,所以这里通过promise.all
方法,获取多个表单的内容,然后统一处理。
import React, { useImperativeHandle, forwardRef } from "react";
import { Form, Input } from "antd";
const TemplateForm1 = (props, ref) => {
const { formItemLayout } = props;
const [form] = Form.useForm();
useImperativeHandle(ref, () => ({
commitForm: (cb) => {
handleCommit(cb);
}
}));
const handleCommit = async (cb) => {
try {
const values = await form.validateFields();
cb(values);
} catch (err) {
console.log(err);
}
};
return (
<Form form={form} {...formItemLayout}>
<Form.Item
name="Name"
label="名称"
rules={[{ required: true, message: "请输入名称" }]}
>
<Input placeholder="点输入名称" />
</Form.Item>
</Form>
);
};
export default forwardRef(TemplateForm1);
复制代码
这个组件是我们定义的表单模版,正常读取后,通过async
和await
获取表单内容,最后再通过commitForm
方法,返回给父组件。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END