第一次写react项目,也是第一次使用antd组件库。对新手(我本人)体验感不算好,甚至有些糟糕。不过问题总算曲折费时的解决了,特此记录一下。如果大家有更好的解决方案,也欢迎评论指教。
1.form-item中使用多个组件(如Select)form-item无法正确接收组件返回的值。
解决方法:利用useState,建立相关变量,最后赋值到form的values对象中。(吐槽一下,Select组件居然没有name属性,最后利用key携带name+序号,然后字符串截取获得name值)
特别注意:在赋值过程中善用展开运算符,避免赋值过程中破坏数据结构。
import React, { useState } from "react";
const [data, setData] = useState({
experience: "",
education: "",
});
const onFinish = (values) => {
values.experience = data.experience; //手动让form携带未识别的value
values.education = data.education;
console.log("Received values of form: ", values);
};
const onSelectMul = (value, e) => {
const name = e.key.slice(0, e.key.length - 1); //获取name
console.log(name, value);
setData((preData) => {
return {
...preData, //保证数据结构稳定,也可以不确定参数进行赋值
[name]: value, //[name]等同于data.name
};
});
console.log(data);
};
2.form-item缺少value时正常使用验证机制。
解决方法:利用form.setFieldsValue
(动态修改表单值)、onFinishFailed(验证失败回调)。此时对form-item设置name属性(为了接收验证的字段),在onFinishFailed中直接进行逻辑判断利用form.setFieldsValue修改表单值。之后利用values.values调用onFinsh,就能实现丝滑连招啦。
const [form] = Form.useForm(); //新建form实例,调用form.setFieldsValue使用
const onFinishFailed = (values) => { //表单验证失败回调
if (data.experience && data.education) { //如果此处子组件携带值,我们将改字段赋值
form.setFieldsValue({
experienceEducation: "pass",
});
onFinish(values.values); //回调form验证成功
}
console.log(values);
console.log(values.values.experienceEducation);
};
3.完整代码
import { Form } from "antd";
import React, { useState } from "react";
import { Select, Form } from "antd";
function Demo() {
const [data, setData] = useState({
experience: "",
education: "",
});
const [form] = Form.useForm();
const onFinishFailed = (values) => {
if (data.experience && data.education) {
form.setFieldsValue({
experienceEducation: "pass",
});
onFinish(values.values);
}
console.log(values);
console.log(values.values.experienceEducation);
};
const onFinish = (values) => {
values.experience = data.experience;
values.education = data.education;
console.log("Received values of form: ", values);
};
const onSelectMul = (value, e) => {
const name = e.key.slice(0, e.key.length - 1);
console.log(name, value);
setData((preData) => {
return {
...preData,
[name]: value,
};
});
console.log(data);
};
return (
<Form onFinish={onFinish} onFinishFailed={onFinishFailed} form={form}>
<Form.Item
name="experienceEducation"
label="经验学历"
className={styles.loginForm}
rules={[
{
required: true,
message: "请选择经验学历!",
},
]}
>
<Select
name="education"
onChange={onSelectMul}
placeholder="选择学历"
className={styles.SelectMul}
options={[
{ value: "不限", label: "不限", key: "education1" },
{ value: "大专", label: "大专", key: "education2" },
{ value: "本科", label: "本科", key: "education3" },
{ value: "硕士", label: "硕士", key: "education4" },
{ value: "博士", label: "博士", key: "education5" },
]}
></Select>
<Select
name="experience"
onChange={onSelectMul}
placeholder="选择经验"
className={styles.SelectMul}
options={[
{ value: "不限", label: "不限", key: "experience1" },
{ value: "在校生", label: "在校生", key: "experience2" },
{ value: "应届生", label: "应届生", key: "experience3" },
]}
></Select>
</Form.Item>
</Form>
);
}
export default Demo;
4.总结
本次使用form表单组件遇见最大的问题就是当form-item包含多个子组件时,value的接收和处理。当只包含一个子组件时,form-item会默认将子组件携带的value传递给自身,多子组件时我采取state存放子组件的value,并在提交时赋值给form表单,让其携带完整数据。
中间遇见的一个小坑,usestate为异步修改,控制台上打印的数据是上一次的,采取了一些尝试,如useEffect、自定义hook、箭头函数回掉等,并没有成效。原因是,这些操作目的在于获取最新数据,打印可能还是异步的(我觉得)。但是此处对我的操作并不影响(白费功夫研究同步修改了),在提交表单时,组件已经重新渲染,此时数据获取的为最新的数据。
之前没使用展开运算符,导致data的数据结构变成层层嵌套的形式,或只保留一个成员变量的key:value。后续赋值时!切记注意此问题!
最初是想利用修改表单的字段form.setFieldsValue
来修改,没有成功。后面在api中调用api成功了,不知道是不是因为未识别的子组件调用。同时组件某些属性无法获取到变量的值,如help,rules内的required等。