React表单验证失效:错误输入仍可提交问题求助
联系表单验证失效问题排查与修复
核心错误点
- 提交按钮类型错误:按钮设置为
type='button'并绑定onClick,绕过了浏览器默认的HTML5表单验证机制,点击时直接执行handleSubmit,完全不检查输入合法性。 - 逻辑运算符误用:按钮
disabled属性用了位或运算符|,正确应该用逻辑或||(虽当前场景未直接导致提交,但逻辑不严谨)。 - 提交函数未做有效性校验:
handleSubmit里没有手动验证表单有效性,直接执行邮件发送和状态切换,导致非法输入也会触发提交流程。 - 成功提示时机错误:
setShow(false)放在emailjs.send外部,不管邮件发送成功与否都会显示“已发送”,不符合预期。
修复步骤
1. 修正提交按钮配置
将按钮的type改为submit,移除onClick绑定,让表单的onSubmit接管提交逻辑,触发浏览器默认验证:
<button disabled={!name || !email || !subject || !message } className='message-submit-btn' onBlur={handleBlur} type='submit' > SUBMIT MESSAGE </button>
2. 完善handleSubmit的验证逻辑
在函数开头先检查表单有效性,若无效则触发验证提示并终止后续流程;同时把setShow(false)移到邮件发送成功的回调里:
const handleSubmit = (e) => { e.preventDefault(); // 手动触发表单验证,若无效则终止 const form = e.target; if (!form.checkValidity()) { form.reportValidity(); return; } const serviceId = ''; const templateId = ''; const publicKey = ''; const templateParams = { from_name: name, from_email: email, from_subject: subject, to_name: 'Lucy', message: message, } emailjs.send(serviceId, templateId, templateParams, publicKey) .then((response) => { console.log('Email sent successfully', response); setName(''); setEmail(''); setSubject(''); setMessage(''); // 仅发送成功时显示确认信息 setShow(false); }) .catch((error) => { console.error('Error sending email:', error) }) }
3. 优化验证提示的触发逻辑(可选)
在用户输入时同步更新focused状态,让错误提示更及时:
const handleChange = (e) => { const { name, value } = e.target; // 根据输入框name更新对应state switch(name) { case 'from_name': setName(value); break; case 'from_email': setEmail(value); break; case 'from_subject': setSubject(value); break; case 'message': setMessage(value); break; default: break; } // 输入时标记为已聚焦,实时触发验证提示 setFocused(prev => ({...prev, [name]: true})); }
随后将每个输入框的onChange替换为handleChange即可。
完整修改后的ContactForm.jsx示例
import { useState } from 'react'; import emailjs from '@emailjs/browser'; import CircleCheckBig from './path-to-your-icon'; // 替换为实际图标路径 const ContactForm = () => { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [subject, setSubject] = useState(''); const [message, setMessage] = useState(''); const [show, setShow] = useState(true); const [ focused, setFocused ] = useState({}); const handleBlur = (e) => { setFocused(prev => ({...prev, [e.target.name]: true})) } const isFocused = (name) => { return focused[name] === true } const handleChange = (e) => { const { name, value } = e.target; switch(name) { case 'from_name': setName(value); break; case 'from_email': setEmail(value); break; case 'from_subject': setSubject(value); break; case 'message': setMessage(value); break; default: break; } setFocused(prev => ({...prev, [name]: true})); } const handleSubmit = (e) => { e.preventDefault(); const form = e.target; if (!form.checkValidity()) { form.reportValidity(); return; } const serviceId = ''; const templateId = ''; const publicKey = ''; const templateParams = { from_name: name, from_email: email, from_subject: subject, to_name: 'Lucy', message: message, } emailjs.send(serviceId, templateId, templateParams, publicKey) .then((response) => { console.log('Email sent successfully', response); setName(''); setEmail(''); setSubject(''); setMessage(''); setShow(false); }) .catch((error) => { console.error('Error sending email:', error) }) } return ( <> {show ? ( <form onSubmit={handleSubmit} className='form'> <div className='textbox name'> <input name='from_name' value={name} type='text' placeholder='Your Name' pattern='^[A-Za-z]{2,16}$' onBlur={handleBlur} onChange={handleChange} data-focused={isFocused('from_name').toString()} required /> <span>Please fill in this field</span> </div> <div className='textbox email'> <input name='from_email' value={email} type='email' placeholder='Your Email' onBlur={handleBlur} onChange={handleChange} data-focused={isFocused('from_email').toString()} required /> <span>Please fill in this field</span> </div> <div className='textbox subject'> <select name='from_subject' value={subject} onBlur={handleBlur} onChange={handleChange} data-focused={isFocused('from_subject').toString()} required > <option value=''>What is your enquiry about?</option> <option value='General'>General</option> <option value='Review'>Review</option> <option value='Business'>Business</option> <option value='Other'>Other</option> </select> <span>Please select an appropiate subject</span> </div> <div className='textbox message'> <textarea name='message' value={message} cols="30" rows="15" minLength={100} placeholder='What is your message to us about? Any specifics, please add here.' onBlur={handleBlur} onChange={handleChange} data-focused={isFocused('message').toString()} required /> <span>Message needs to be at least 100 characters long</span> </div> <div > <button disabled={!name || !email || !subject || !message } className='message-submit-btn' onBlur={handleBlur} type='submit' > SUBMIT MESSAGE </button> </div> </form> ) : ( <div className='sent-confirm'> <CircleCheckBig style={{color: 'var(--btn-green)'}} strokeWidth={0.4} size={400}/> <p className='sent-confirm-text'>Message Sent!</p> </div> )} </> ); } export default ContactForm
内容的提问来源于stack exchange,提问作者ryanl
相关产品推荐
相关产品推荐

