reactjsrecaptchareact-google-recaptcha

Google ReCaptcha: react-google-recaptcha not verifying correctly


I have the following React component for a contact form:

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
        })
    };


    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,
        })
    }

    handleSubmit = event => {

        const url = 'https://xxxxxxxx.execute-api.eu-central-1.amazonaws.com/dev/email/send';

        this.setState({
            submitting: true
          })

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

        if (this.state.verified) {
            fetch(url, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload),
            })
            .then(this.handleSuccess)
            .catch(error => alert(error))
            event.preventDefault()
        }
        else {this.setState({reply: "Please verify the ReCaptcha."})}
    }

    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="formBasicEmail">
                                    <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="formBasicEmail">
                                    <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" 
                                        type="text" 
                                        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 ? <p id="error" className="error">{this.state.reply}</p> : null }
                                { this.state.showSuccess ? <p id="success" className="success">Thank you, we will be in touch asap.</p> : null }
                                <Button id="submit" variant="primary" type="submit">
                                    Submit
                                </Button>
                            </Form>
                        </Col>
                    </Row>
                </Container>
            </section>
        )
    }
}

export default Contact


Desired behaviour

I'm using react-google-recaptcha (https://www.npmjs.com/package/react-google-recaptcha) for Recaptcha verification and inserted the component top of the submit button:

<ReCAPTCHA
    className="g-recaptcha"
    sitekey="XXXXXXXXXXXXXXXXXXXXX"
    onChange={this.onChange}
    theme="dark"
/>

The onChange function should set state.verfied == true

onChange = (value) => {
    console.log("Captcha value:", value);
    this.setState({
        verified: true
    })
};

so that this part of handledSubmit() fires if the reCaptcha was completed and the form gets submitted without page reload:

if (this.state.verified) {
    fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload),
    })
    .then(this.handleSuccess)
    .catch(error => alert(error))
    event.preventDefault()
}

otherwise it should render this.state.reply: "Please verify the ReCaptcha." above the submit button.


What it does instead

The submit button works without completing the reCaptcha and submits the form. It reloads the page to http://localhost:8000/?name=Test&email=test&company=test&content=test&g-recaptcha-response=

I know that my workaround using state probably isn't the correct way of using this module, but the react-google-recaptcha docs leave no hint on how to correctly integrate the verification with the reCaptcha API.

Happy for any support on this. Thanks!


Solution

  • I needed to change the onChange function to store the reCaptchaResponse like so:

    onChange = (result) => {
    
        this.setState({
            verified: true,
            reCaptchaResponse: result,
        }) 
    };
    

    And secondly I updated the condition in handleSubmit to check for verification much earlier and also integrate the reCaptchaResponse in the payload like so:

    handleSubmit = event => {
        
        if (this.state.verified) {
            const url = 'https://xxxxxxxxxx.execute-api.eu-central-1.amazonaws.com/dev/email/send';
    
            this.setState({
                submitting: true
            })
            
            const payload = {
                name: this.state.name,
                email: this.state.email,
                company: this.state.company,
                content: this.state.content,
                result: this.state.reCaptchaResponse
            }
    
            fetch(url, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload),
            })
            .then(this.handleSuccess)
            .catch(error => alert(error))
            event.preventDefault()
        } else {
            this.setState({
                reply: "Please verify the ReCaptcha"
            })
        }
    }