如何在React中编写正确的表单校验?现有异常问题求助
问题根因
- 问题1(空提交优先触发手机号错误):你所有表单字段的初始state为
undefined,正则校验时undefined会被隐式转为字符串"undefined",刚好符合公司、姓名的正则规则,校验直接通过到手机号环节才失败,所以只弹出手机号错误提示。同时你给输入框加了原生required属性,自定义校验和原生校验逻辑冲突也会导致提示顺序异常。 - 问题2(未填公司可提交):你判断空值的逻辑是
company === "",如果用户从未操作过公司输入框,company的值始终是初始的undefined,和空字符串判断不相等,空值校验直接跳过,同时"undefined"符合公司名称正则规则,所以校验通过允许提交。
另外你手机号正则加了全局g修饰符,多次调用test方法时会因为lastIndex偏移出现校验异常。
修复步骤
- 所有表单相关state初始化时设置默认值为空字符串,避免
undefined隐式转换问题:
// 修正前 const [company, setCompany] = useState(); // 修正后 const [company, setCompany] = useState(''); // 姓名、手机号、邮箱的state都按此规则修改初始值
- 去掉所有
input标签上的required属性,用你自定义的校验逻辑即可,避免和原生校验冲突。 - 移除手机号正则的全局
g修饰符:
// 修正前 const rePhone = /\+?[0-9]+([0-9]|\/|\(|\)|\-| ){10,}/g; // 修正后 const rePhone = /\+?[0-9]+([0-9]|\/|\(|\)|\-| ){10,}/;
- 调整
onClick校验逻辑,先做非空判断,所有字段校验全部执行完成后再判断是否允许提交,不要中途return:
const onClick = (e) => { const reCompanyName = /^[a-zA-Z](?:[^0-9\s\x00-\x1F]|[ \t]){1,79}$/; const reName = /[A-Za-z]{1,50}/; const reEmail = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/; const rePhone = /\+?[0-9]+([0-9]|\/|\(|\)|\-| ){10,}/; let hasError = false; // 公司校验 if (!company.trim()) { setCompanyValidate(true); hasError = true; } else if (!reCompanyName.test(company)) { setCompanyValidate(true); hasError = true; } else { setCompanyValidate(false); } // 姓名校验 if (!name.trim()) { setNameValidate(true); hasError = true; } else if (!reName.test(name)) { setNameValidate(true); hasError = true; } else { setNameValidate(false); } // 手机号校验 if (!phone.trim()) { setPhoneValidation(true); hasError = true; } else if (!rePhone.test(phone)) { setPhoneValidation(true); hasError = true; } else { setPhoneValidation(false); } // 邮箱校验 if (!email.trim()) { setEmailValidate(true); hasError = true; } else if (!reEmail.test(email)) { setEmailValidate(true); hasError = true; } else { setEmailValidate(false); } // 有错误直接终止提交 if (hasError) return; // 原有提交逻辑 setCompanyValue(company); setNameValue(name); setPhoneValue(phone); setEmailValue(email); setCompany(""); setName(""); setPhone(""); setEmail(""); setInput(false); setMessage(false); setSubMessage(false); setLine(true); setBtn(false); setTimeout(() => { setInput(true); setMessage(true); setSubMessage(true); setLine(false); setBtn(true); setCompanyValidate(false); setNameValidate(false); setPhoneValidation(false); setEmailValidate(false); }, 5000); };
内容的提问来源于stack exchange,提问作者Spactex
相关产品推荐
相关产品推荐

