React应用中Bootstrap表单首次点击Submit不触发问题求助
问题核心
你的问题出在React状态更新是异步的:在sendEmail函数里,调用setValidated(true)后马上判断validated === true,此时validated还没完成更新,第一次点击时不会执行邮件发送逻辑;第二次点击时validated已经变成true,才会触发发送,所以需要双击才能成功。
解决方案1:直接用表单验证结果(推荐)
不用依赖validated状态判断是否发邮件,直接拿表单checkValidity()的返回值,验证通过就立即调用email.js,逻辑更直接:
import React, { useState, useRef } from "react"; import { Col, Button, Form, Card, InputGroup } from "react-bootstrap"; import emailjs from "@emailjs/browser"; const ContactForm = () => { const refForm = useRef(); const [validated, setValidated] = useState(false); const sendEmail = (e) => { e.preventDefault(); e.stopPropagation(); const form = e.currentTarget; // 先检查表单是否有效 const isFormValid = form.checkValidity(); // 设置validated状态,触发Bootstrap的错误提示样式 setValidated(true); if (isFormValid) { // 验证通过,执行email.js发送逻辑 emailjs.sendForm('你的服务ID', '你的模板ID', refForm.current, '你的公钥') .then((result) => { console.log("邮件发送成功:", result.text); // 可选:发送成功后重置表单 form.reset(); setValidated(false); }, (error) => { console.log("邮件发送失败:", error.text); }); } }; return ( <Form ref={refForm} onSubmit={sendEmail} autoComplete="on" noValidate validated={validated} > <Form.Label>全名*</Form.Label> <Form.Group> <InputGroup hasValidation> <Form.Control name="name" type="text" required minLength={3} maxLength={20} /> <Form.Control.Feedback type="invalid"> 请输入至少3个字符的全名 </Form.Control.Feedback> </InputGroup> </Form.Group> <Form.Label>邮箱地址*</Form.Label> <Form.Group> <InputGroup hasValidation> <Form.Control name="email" type="email" required /> <Form.Control.Feedback type="invalid"> 请输入有效的邮箱格式 </Form.Control.Feedback> </InputGroup> </Form.Group> <Button type="submit" value="send"> 提交 </Button> </Form> ); }; export default ContactForm;
解决方案2:用useEffect监听状态
如果一定要用useEffect,可以监听validated和表单提交状态,当两者都满足时触发发送:
import React, { useState, useRef, useEffect } from "react"; import { Col, Button, Form, Card, InputGroup } from "react-bootstrap"; import emailjs from "@emailjs/browser"; const ContactForm = () => { const refForm = useRef(); const [validated, setValidated] = useState(false); const [isSubmitted, setIsSubmitted] = useState(false); // 监听validated和isSubmitted状态变化 useEffect(() => { if (validated && isSubmitted) { // 验证通过且表单已提交,执行发送 emailjs.sendForm('你的服务ID', '你的模板ID', refForm.current, '你的公钥') .then((result) => { console.log("邮件发送成功:", result.text); // 重置状态,避免重复触发 setIsSubmitted(false); refForm.current.reset(); setValidated(false); }, (error) => { console.log("邮件发送失败:", error.text); setIsSubmitted(false); }); } }, [validated, isSubmitted]); const sendEmail = (e) => { e.preventDefault(); e.stopPropagation(); const form = e.currentTarget; const isFormValid = form.checkValidity(); setValidated(true); if (isFormValid) { // 标记表单已提交,触发useEffect setIsSubmitted(true); } }; return ( <Form ref={refForm} onSubmit={sendEmail} autoComplete="on" noValidate validated={validated} > {/* 表单内容和方案1一致 */} <Form.Label>全名*</Form.Label> <Form.Group> <InputGroup hasValidation> <Form.Control name="name" type="text" required minLength={3} maxLength={20} /> <Form.Control.Feedback type="invalid"> 请输入至少3个字符的全名 </Form.Control.Feedback> </InputGroup> </Form.Group> <Form.Label>邮箱地址*</Form.Label> <Form.Group> <InputGroup hasValidation> <Form.Control name="email" type="email" required /> <Form.Control.Feedback type="invalid"> 请输入有效的邮箱格式 </Form.Control.Feedback> </InputGroup> </Form.Group> <Button type="submit" value="send"> 提交 </Button> </Form> ); }; export default ContactForm;
关键提醒
- React状态更新是异步操作,不要在调用
setState后立刻读取该状态的值做判断,这时候值还没更新 - Bootstrap的
validated属性只是用来控制错误提示的显示,不需要用它来决定是否执行发送逻辑 - 优先选方案1,逻辑更简洁,避免额外的状态监听
内容的提问来源于stack exchange,提问作者Julie
相关产品推荐
相关产品推荐

