Adding ReCaptcha to React Comments

Oct 22, 2018

React Comments is a Disqus-like comment feature for Drupal 8. It is a much more beautiful alternative to the Ajax Comments module, which we had migrated to Drupal 8 as an initial solution. The only thing missing in React Comments for our purposes was ReCaptcha integration.

There are various ReCaptcha components for React. We tried a few and decided on react-recaptcha-google. We added that package to the project (yarn add react-recaptcha-google) and added an implementation of that component:

cd react_comments/js/src/
cat src/components/CommentReacaptcha.js
import React, { Component } from 'react';
import './CommentReacaptcha.css';
import { ReCaptcha } from 'react-recaptcha-google'

class CommentReacaptcha extends Component {
  constructor(props, context) {
    super(props, context);
    this.onLoadRecaptcha = this.onLoadRecaptcha.bind(this);
    this.verifyCallback = this.verifyCallback.bind(this);
  }

  componentDidMount() {
    if (this.captchaDemo) {
      this.captchaDemo.reset();
    }
  }

  resetCaptcha() {
    this.captchaDemo.reset();
  }

  onLoadRecaptcha() {
    if (this.captchaDemo) {
      this.captchaDemo.reset();
    }
  }

  verifyCallback(recaptchaToken) {
    this.props.verified(recaptchaToken)
  }

  render() {
    let containerClasses = ['rc_comment-recap-container'];

    return (
      <div className={containerClasses}>
        <ReCaptcha
          ref={(el) => {this.captchaDemo = el;}}
          size="normal"
          render="explicit"
          sitekey="<our-site-key>"
          onloadCallback={this.onLoadRecaptcha}
          verifyCallback={this.verifyCallback}
        />
      </div>
    )
  }

};

export default CommentReacaptcha;

We imported the component to App.js:

cat src/App.js | awk 'NR >= 9 && NR <= 10'
import {loadReCaptcha} from 'react-recaptcha-google'
import CommentReacaptcha from './components/CommentReacaptcha';

We added state variable that will indicate whether captcha is verified or not:

cat src/App.js | awk 'NR >= 12 && NR <= 22'
class App extends Component {
  state = {
    currentUser: {
      hasPermission: () => false
    },
    comments: null,
    settings: null,
    loading: true,
    openMenu: null,
    captchaVerified: false,
  };

We added a callback method that will update the state variable:

cat src/App.js | awk 'NR >= 180 && NR <= 182'
  captchaVerified(token) {
    this.setState({captchaVerified: !!token})
  }

Added component to render:

cat src/App.js | awk 'NR >= 203 && NR <= 203'
        <CommentReacaptcha verified={this.captchaVerified.bind(this)} />

Finally, added an attribute in CommentBox component to disable comment button if captcha is not verified:

cat src/components/CommentBox.js | awk 'NR >= 209 && NR <= 209'
                { (type === 'comment' && user && userCanPostComments) && <button disabled={!this.props.captchaVerified} onClick={this.handlePost.bind(this)} className="rc_add-comment">Post your comment{user.name && ` as ${user.name}`}</button> }

One last issue:

Once in a while, the browser would throw an error complaining something about grecaptcha.render not being a function. The fix is to check for that in the module. We first tried to patch the module with npm but there is a mismatch betweeen the version of react-recaptcha-google in npmjs.com and that in GitHub. So we forked the repo and added our own patch to it:

git clone git@github.com:henokmikre/react-recaptcha-google.git
cd react-recaptcha-google/
git checkout 2718b3675098a6b9856aaf1af4df57ed10df6011 -b v2
vi src/ReCaptcha.js
yarn install
yarn build
git commit -am "Added error handling for grecaptcha.render."

Here is the exact change (which was actually taken from another npm package appleboy/react-recaptcha):

diff --git a/src/ReCaptcha.js b/src/ReCaptcha.js
index 674e746..8df8a7a 100644
--- a/src/ReCaptcha.js
+++ b/src/ReCaptcha.js
@@ -37,7 +37,11 @@ const defaultProps = {
     badge: 'bottomright',
 };

-const isReady = () => typeof window !== 'undefined' && typeof window.grecaptcha !== 'undefined';
+const isReady = () =>
+  typeof window !== "undefined"
+  && typeof window.grecaptcha !== 'undefined'
+  // need to check for presence of render, because reCaptcha creates { ready } first
+  && !!window.grecaptcha.render;
git push origin v2

We then added the forked version of react-recaptcha-google in react_comments yarn.lock. A better approach would be to use a component based on ReCaptcha v3.

Last step was to rebuild the React. But we first need to make sure we have the build tools:

# Install nodejs
curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -
sudo yum install -y nodejs

# Install yarn
curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
sudo yum install -y yarn

# Install packages
yum install

Now we can build:

./build.php

React Comments in action

That’s all!

Resources

Henok Mikre


Naod Yeheyes


Recent Posts

About

BLEN Corp is a small, minority, and veteran-owned information technology firm located in Washington D.C. Since 2004, we have been ahead of the curve in early adaption and implementation of cutting edge technologies including web and mobile development, service-oriented architecture, and other innovative web based solutions. Look at some of our projects.

Social Links

Our Bunker

WeWork Wonder Bread Factory
641 S St. NW
3rd Floor
Washington, DC 20001
United States.