Skip to content

Instantly share code, notes, and snippets.

@ivansnek
Last active October 20, 2019 03:45
Show Gist options
  • Save ivansnek/8b69055ddef6b6a43769ed95bd7360f8 to your computer and use it in GitHub Desktop.
Save ivansnek/8b69055ddef6b6a43769ed95bd7360f8 to your computer and use it in GitHub Desktop.
// Validate if Google ReCaptcha library is loaded on window scope
export function isReCaptchaReady () {
return typeof window !== 'undefined'
&& typeof window.grecaptcha !== 'undefined'
&& typeof window.grecaptcha.render === 'function';
}
// Dinamically inject a `script` tag and load Google ReCaptcha library
export function injectRecaptchaScript() {
const id = 'g-recaptcha-container';
const existing = document.getElementById(id);
if (!existing) {
const script = document.createElement("script");
script.id = id;
script.async = true;
script.defer = true;
script.src = 'https://www.google.com/recaptcha/api.js';
document.body.appendChild(script);
}
}
import React, { useState, useEffect } from 'react'
import { useInterval } from './useInterval';
import { injectRecaptchaScript, isReCaptchaReady } from './g-recaptcha';
import './styles.css';
/**
* Simple auto-loadable Google ReCaptcha component
*
* @param {object} component properties
*/
export function ReCaptcha({ sitekey, onVerify }){
const [ready, setReady] = useState(false);
// Set interval to check Google ReCaptcha readiness status
useInterval(addReCaptcha, ready ? null : 1000);
useEffect(() => {
// Set local function to global scope per Google Recaptcha requirements;
window.onCaptchaCallback = onCaptchaCallback;
// Unset when component unmounts
return () => window.onCaptchaCallback = undefined;
}, [ready]);
// Dinamically Inject Google ReCaptcha script tag
function addReCaptcha() {
if (!isReCaptchaReady()) {
injectRecaptchaScript();
} else {
setReady(true);
}
}
function onCaptchaCallback(response) {
if (typeof onVerify === 'function') {
onVerify(!!response);
}
}
return (
<div
className="g-recaptcha"
data-sitekey={sitekey}
data-callback="onCaptchaCallback"
/>
);
};
// Custom CSS
.g-recaptcha > div {
margin: 0 auto;
}
import { useEffect, useRef } from 'react';
// SetInterval workaround with Hooks by Dan Abramov:
// https://overreacted.io/making-setinterval-declarative-with-react-hooks/
export function useInterval(callback, delay) {
const savedCallback = useRef();
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment