React中使用Ant Design校验动态邮箱字符串数组的正确实现方式
邮箱动态列表校验正确方案(Ant Design 实现)
原有实现问题根因
- 所有
Form.Item的name均为固定值email,Antd Form无法识别为独立字段,没法单独触发每个输入框的校验 - 使用数组索引作为
key,删除元素后后续元素索引前移,手动维护的invalidArrayIndexes存储的索引和实际字段对应关系错乱 - 脱离Antd Form自带的状态管理和校验能力手动维护表单状态,重复造轮子同时容易出现状态同步问题
正确实现思路
直接使用Antd Form内置的Form.List组件处理动态数组表单,天然支持动态增删字段、独立校验每个字段、自动维护字段唯一标识,不需要手动维护校验索引:
- 首次提交才触发校验:初始化时设置表单
validateTrigger为空数组,输入时不触发校验,第一次提交调用表单校验方法后,再将validateTrigger改为onChange实现后续输入实时校验 - 至少保留1个邮箱:删除按钮判断当前字段列表长度,小于等于1时禁用删除
- 邮箱合法性校验:在校验规则中统一配置必填、格式正则校验
- 邮箱去重校验:自定义校验器,对比当前输入值和其他邮箱字段值是否重复
修正后完整代码
import { Button, Form, Input } from "antd"; import { useState } from "react"; const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const MyForm = () => { const [form] = Form.useForm(); const [firstSubmit, setFirstSubmit] = useState(false); // 邮箱重复校验自定义规则 const uniqueEmailValidator = (rule, value) => { const allEmails = form.getFieldValue('emails').map(item => item.value.trim()); const duplicateCount = allEmails.filter(email => email === value.trim()).length; if (duplicateCount > 1) { return Promise.reject(new Error('邮箱不能重复')); } return Promise.resolve(); }; // 提交逻辑 const onSubmit = async () => { if (!firstSubmit) { setFirstSubmit(true); } try { const values = await form.validateFields(); const emails = values.emails.map(item => item.value.trim()); console.log("提交的邮箱列表:", emails); // 后续提交逻辑 } catch (error) { // 校验失败自动展示错误提示,无需额外处理 } }; return ( <Form form={form} initialValues={{ emails: [{ value: '' }] // 初始至少1个邮箱输入框 }} validateTrigger={firstSubmit ? 'onChange' : []} style={{ maxWidth: 600 }} > <Form.List name="emails"> {(fields, { add, remove }) => ( <> {fields.map((field) => ( <Form.Item key={field.key} // 用Form.List提供的唯一key,避免增删后索引错乱 label="邮箱" name={[field.name, 'value']} // 每个输入框独立name rules={[ { required: true, message: 'Please enter your email!' }, { pattern: emailRegex, message: '邮箱格式不正确' }, { validator: uniqueEmailValidator } ]} > <Input style={{ width: 300, marginRight: 8 }} placeholder="请输入邮箱" /> <Button type="text" onClick={() => remove(field.name)} disabled={fields.length <= 1} // 至少保留1个邮箱 > 删除邮箱 </Button> </Form.Item> ))} <Button type="dashed" onClick={() => add({ value: '' })} block style={{ marginBottom: 16 }}> 新增邮箱 </Button> </> )} </Form.List> <Form.Item> <Button type="primary" onClick={onSubmit}> 发送邮件 </Button> </Form.Item> </Form> ); }; export default MyForm;
问题修复说明
- 新增元素无法触发必填提示:每个输入框有独立的
name,新增字段自动纳入表单校验体系,首次提交后新增空字段会自动展示必填错误 - 增删元素后校验索引混乱:使用
Form.List提供的唯一field.key作为列表项key,增删元素不会改变已有字段的唯一标识,校验状态不会错乱 - 不需要手动维护邮箱数组、无效索引等状态,所有状态和校验逻辑由Antd Form统一管理,避免状态同步错误
内容的提问来源于stack exchange,提问作者Esr
相关产品推荐
相关产品推荐

