React表单验证通过后无法使用Email.js发送的问题解决
React表单验证与Email.js发送修复方案
问题描述
我在React应用中尝试在表单验证完成后通过Email.js发送表单数据,但即使没有错误,表单也无法发送。需求是:
- 若至少一个字段未填写,显示错误提示且不发送表单
- 所有字段填写完成后,发送表单并向用户展示成功提示
原代码如下:
import React, { useState, useRef, useEffect } from "react"; import "../CSS/form.css"; import Checkbox from "./Checkbox"; import emailjs from "@emailjs/browser"; const Form = () => { const formRef = useRef(); const initialValues = { panna_mloda: "", pan_mlody: "", numer_kontaktowy: "", email: "", data: "", miejsce_slubu: "", miejsce_wesela: "", goscie: "", budzet: "", }; const [formValues, setFormValues] = useState(initialValues); const [formErrors, setFormErrors] = useState({}); const [isSubmit, setIsSubmit] = useState(false); const handleChange = (e) => { const { name, value } = e.target; setFormValues({ ...formValues, [name]: value }); }; const validate = (values) => { const errors = {}; if (!values.panna_mloda) { errors.panna_mloda = "Proszę wprowadzić imię Panny młodej"; } if (!values.pan_mlody) { errors.pan_mlody = "Proszę wprowadzić imię Pana młodego"; } if (!values.numer_kontaktowy) { errors.numer_kontaktowy = "Proszę wprowadzić numer kontaktowy"; } if (!values.email) { errors.email = "Proszę wprowadzić adres mailowy"; } if (!values.data) { errors.data = "Proszę wprowadzić datę ślubu"; } if (!values.miejsce_slubu) { errors.miejsce_slubu = "Proszę wprowadzić miejsce ślubu"; } if (!values.miejsce_wesela) { errors.miejsce_wesela = "Proszę wprowadzić miejsce wesela"; } if (!values.goscie) { errors.goscie = "Proszę wprowadzić przewidywaną liczbę gości"; } if (!values.budzet) { errors.budzet = "Proszę wprowadzić planowany budżet na dekorację"; } return errors; }; const handleSubmit = (e) => { e.preventDefault(); setFormErrors(validate(formValues)); setIsSubmit(true); if (Object.keys(formErrors).length === 0 && isSubmit) { emailjs .sendForm( "service_*****", "template_*****", formValues.current, "2aRB3MFBn*****" ) .then( (result) => { console.log(result.text); }, (error) => { console.log(error.text); } ); } }; useEffect(() => { console.log(formErrors); if (Object.keys(formErrors).length === 0 && isSubmit) { console.log(formValues); } }, [formErrors]);
问题分析与修复步骤
- 状态更新异步导致判断失效:
setFormErrors是异步操作,在handleSubmit中直接判断formErrors长度时,状态还未更新,无法得到正确的验证结果。 - Email.js参数错误:
sendForm需要传入DOM表单元素(formRef.current),而非状态对象formValues(它没有current属性)。 - 缺失用户反馈:原代码没有成功/失败的用户提示逻辑。
修改后的完整代码
import React, { useState, useRef, useEffect } from "react"; import "../CSS/form.css"; import Checkbox from "./Checkbox"; import emailjs from "@emailjs/browser"; const Form = () => { const formRef = useRef(); const initialValues = { panna_mloda: "", pan_mlody: "", numer_kontaktowy: "", email: "", data: "", miejsce_slubu: "", miejsce_wesela: "", goscie: "", budzet: "", }; const [formValues, setFormValues] = useState(initialValues); const [formErrors, setFormErrors] = useState({}); const [isSubmit, setIsSubmit] = useState(false); const [submitSuccess, setSubmitSuccess] = useState(false); // 新增成功状态 const handleChange = (e) => { const { name, value } = e.target; setFormValues({ ...formValues, [name]: value }); // 输入时清除成功提示 if (submitSuccess) setSubmitSuccess(false); }; const validate = (values) => { const errors = {}; // 增加trim处理,过滤纯空格输入 if (!values.panna_mloda.trim()) { errors.panna_mloda = "Proszę wprowadzić imię Panny młodej"; } if (!values.pan_mlody.trim()) { errors.pan_mlody = "Proszę wprowadzić imię Pana młodego"; } if (!values.numer_kontaktowy.trim()) { errors.numer_kontaktowy = "Proszę wprowadzić numer kontaktowy"; } if (!values.email.trim()) { errors.email = "Proszę wprowadzić adres mailowy"; } if (!values.data.trim()) { errors.data = "Proszę wprowadzić datę ślubu"; } if (!values.miejsce_slubu.trim()) { errors.miejsce_slubu = "Proszę wprowadzić miejsce ślubu"; } if (!values.miejsce_wesela.trim()) { errors.miejsce_wesela = "Proszę wprowadzić miejsce wesela"; } if (!values.goscie.trim()) { errors.goscie = "Proszę wprowadzić przewidywaną liczbę gości"; } if (!values.budzet.trim()) { errors.budzet = "Proszę wprowadzić planowany budżet na dekorację"; } return errors; }; const handleSubmit = (e) => { e.preventDefault(); // 同步获取验证结果,避免异步状态更新延迟 const errors = validate(formValues); setFormErrors(errors); setIsSubmit(true); }; useEffect(() => { if (isSubmit && Object.keys(formErrors).length === 0) { // 验证通过,发送邮件 emailjs .sendForm( "service_*****", "template_*****", formRef.current, // 修正为表单DOM元素 "2aRB3MFBn*****" ) .then( (result) => { console.log(result.text); setSubmitSuccess(true); // 发送成功后重置表单 setFormValues(initialValues); setIsSubmit(false); }, (error) => { console.log(error.text); alert("Wystąpił błąd podczas wysyłania formularza, spróbuj ponownie."); setIsSubmit(false); } ); } else if (isSubmit) { // 验证不通过,重置提交状态 setIsSubmit(false); } }, [formErrors, isSubmit]); return ( <form ref={formRef} onSubmit={handleSubmit}> {/* Panna młoda字段示例,其他字段按相同逻辑渲染 */} <div className="form-group"> <label>Panna młoda</label> <input type="text" name="panna_mloda" value={formValues.panna_mloda} onChange={handleChange} /> {formErrors.panna_mloda && <span className="error">{formErrors.panna_mloda}</span>} </div> {/* 其他字段省略,请按照上述示例补充 */} {/* 成功提示 */} {submitSuccess && <div className="success-message">Formularz wysłany pomyślnie!</div>} <button type="submit">Wyślij formularz</button> </form> ); }; export default Form;
关键修改说明
- 同步验证结果:在
handleSubmit中直接调用validate获取错误对象,避免异步状态更新导致的判断延迟。 - 修正Email.js参数:将
formValues.current改为formRef.current,确保传入正确的DOM表单元素。 - 新增用户反馈:添加
submitSuccess状态展示成功消息,发送失败时弹出提示框。 - 优化验证逻辑:用
trim()过滤纯空格输入,避免无效提交。 - 表单重置:发送成功后自动清空表单,提升用户体验。
内容的提问来源于stack exchange,提问作者JKukielski
相关产品推荐
相关产品推荐

