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

react-google-recaptcha验证异常:表单未验证即可提交问题求助

修复React联系表单的reCAPTCHA验证问题

Hey,我看了你的代码,发现两个核心问题导致了表单刷新和验证逻辑异常,咱们一步步来修复:

问题根源

  1. 未全局阻止表单默认提交行为
    你当前只在this.state.verified为true时调用event.preventDefault(),但当用户未完成reCAPTCHA验证就点击提交时,代码走到else分支,没有阻止表单的默认提交行为,浏览器就会用GET方式提交表单,导致页面跳转刷新。

  2. 错误提示的显示逻辑颠倒
    当前代码是验证通过时才显示错误提示,这和咱们的需求完全相反——应该是未验证且触发提交时,才显示"Please verify the ReCaptcha."的提示。

修改后的完整代码

import React from 'react'
import ReCAPTCHA from "react-google-recaptcha";
import {Container, Row, Col, Form, Button } from 'react-bootstrap'
import '../styles/contact.css'

class Contact extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = {
      name: '',
      email: '',
      company: '',
      content: '',
      showSuccess: false,
      submitting: false,
      verified: false,
      reply: ''
    };
    this.handleSuccess = this.handleSuccess.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.onChange = this.onChange.bind(this);
  }

  onChange = (value) => {
    console.log("Captcha value:", value);
    this.setState({ verified: true, reply: '' }) // 验证通过时清空错误提示
  };

  handleInputChange = event => {
    const target = event.target
    const value = target.value
    const name = target.name
    this.setState({
      [name]: value,
    })
  }

  handleSuccess = () => {
    this.setState({
      name: '',
      email: '',
      company: '',
      content: '',
      showSuccess: true,
      submitting: false,
      verified: false, // 重置验证状态,方便用户再次提交
      reply: ''
    })
  }

  handleSubmit = event => {
    // 第一步:先阻止表单默认提交行为,不管验证是否通过
    event.preventDefault();
    
    const url = 'https://xxxxxxxx.execute-api.eu-central-1.amazonaws.com/dev/email/send';
    
    // 如果正在提交,直接返回,防止重复提交
    if (this.state.submitting) return;

    const payload = {
      name: this.state.name,
      email: this.state.email,
      company: this.state.company,
      content: this.state.content
    }

    if (this.state.verified) {
      this.setState({ submitting: true, showSuccess: false })
      fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(payload),
      })
      .then(this.handleSuccess)
      .catch(error => {
        alert(error);
        this.setState({ submitting: false, verified: false }) // 失败后重置状态
      })
    } else {
      this.setState({
        reply: "Please verify the ReCaptcha.",
        showSuccess: false
      })
    }
  }

  render() {
    return (
      <section id="contact" name="#contact">
        <Container>
          <Row className="align-items-center">
            <Col lg={{span: 5, order: 1}} xs={{ span: 12, order: 2}} className="form-background">
              <Form id="contact-form-bottom" onSubmit={this.handleSubmit}>
                <h4 className="h4">Don't be shy, say hi!</h4>
                <Form.Group controlId="formBasicName">
                  <Form.Label>Full Name</Form.Label>
                  <Form.Control as="input" type="text" placeholder="Enter your first name & surname" name="name" value={this.state.name} onChange={this.handleInputChange} required />
                </Form.Group>
                <Form.Group controlId="formBasicEmail">
                  <Form.Label>Email address</Form.Label>
                  <Form.Control as="input" type="email" placeholder="Enter your email address" name="email" value={this.state.email} onChange={this.handleInputChange} required />
                  <Form.Text className="text-muted">
                    We'll never share your email with anyone else.
                  </Form.Text>
                </Form.Group>
                <Form.Group controlId="formBasicCompany">
                  <Form.Label>Company Name</Form.Label>
                  <Form.Control as="input" type="text" placeholder="Enter the name of your company" name="company" value={this.state.company} onChange={this.handleInputChange} required />
                </Form.Group>
                <Form.Group controlId="exampleForm.ControlTextarea1">
                  <Form.Label>Details</Form.Label>
                  <Form.Control as="textarea" rows="3" placeholder="How can we help you?" name="content" value={this.state.content} onChange={this.handleInputChange} required />
                </Form.Group>
                <ReCAPTCHA className="g-recaptcha" sitekey="XXXXXXXXXXXXXXXXXXX" onChange={this.onChange} theme="dark" />
                
                {/* 修正错误提示的显示条件:未验证且有错误消息时显示 */}
                { !this.state.verified && this.state.reply && <p id="error" className="error">{this.state.reply}</p> }
                
                { this.state.showSuccess && <p id="success" className="success">Thank you, we will be in touch asap.</p> }
                
                {/* 添加按钮禁用状态,防止重复提交 */}
                <Button id="submit" variant="primary" type="submit" disabled={this.state.submitting}>
                  {this.state.submitting ? "Submitting..." : "Submit"}
                </Button>
              </Form>
            </Col>
          </Row>
        </Container>
      </section>
    )
  }
}

export default Contact

关键修改说明

  1. 全局阻止默认提交:在handleSubmit函数最开头就调用event.preventDefault(),确保所有提交逻辑都由JavaScript处理,不会触发浏览器默认的表单跳转。
  2. 修正错误提示逻辑:把错误提示的显示条件改成!this.state.verified && this.state.reply,只有未验证且存在错误消息时才显示提示。
  3. 优化状态管理:
    • 验证通过时清空错误消息
    • 提交成功或失败后重置verified状态,方便用户再次提交
    • 添加submitting状态判断,防止重复提交,同时给用户显示提交中的状态提示
  4. 修正Form的controlId:原来多个Form.Group用了相同的formBasicEmail,改成了唯一的ID,避免React Bootstrap的内部逻辑冲突。

这样修改后,表单就能按预期工作:未完成reCAPTCHA验证时点击提交,会显示错误提示且不会刷新页面;验证通过后,表单通过fetch提交,页面保持无刷新,提交成功后清空表单并显示成功提示。

内容的提问来源于stack exchange,提问作者Philipp Laurim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 19:37:58