You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React表单验证失效:错误输入仍可提交问题求助

联系表单验证失效问题排查与修复

核心错误点

  1. 提交按钮类型错误:按钮设置为type='button'并绑定onClick,绕过了浏览器默认的HTML5表单验证机制,点击时直接执行handleSubmit,完全不检查输入合法性。
  2. 逻辑运算符误用:按钮disabled属性用了位或运算符|,正确应该用逻辑或||(虽当前场景未直接导致提交,但逻辑不严谨)。
  3. 提交函数未做有效性校验:handleSubmit里没有手动验证表单有效性,直接执行邮件发送和状态切换,导致非法输入也会触发提交流程。
  4. 成功提示时机错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 16:14:54