next-recaptcha-v3
Version:
🤖 Next.js hook to add Google ReCaptcha to your application
62 lines (59 loc) • 2.76 kB
JavaScript
"use client";
import React, { createContext, useContext, useDebugValue, useState, useRef, useEffect, useCallback, useMemo } from 'react';
import Script from 'next/script.js';
import { getRecaptchaScriptSrc } from './utils.js';
const ReCaptchaContext = createContext({
reCaptchaKey: null,
grecaptcha: null,
loaded: false,
error: false,
});
const useReCaptchaContext = () => {
const values = useContext(ReCaptchaContext);
useDebugValue(`grecaptcha available: ${values?.loaded ? "Yes" : "No"}`);
useDebugValue(`ReCaptcha Script: ${values?.loaded ? "Loaded" : "Not Loaded"}`);
useDebugValue(`Failed to load Script: ${values?.error ? "Yes" : "No"}`);
return values;
};
const ReCaptchaProvider = ({ reCaptchaKey: passedReCaptchaKey, useEnterprise = false, useRecaptchaNet = false, language, children, id = "google-recaptcha-v3", strategy = "afterInteractive", src: passedSrc, onLoad: passedOnLoad, onError: passedOnError, ...props }) => {
const [grecaptcha, setGreCaptcha] = useState(null);
const [loaded, setLoaded] = useState(false);
const [error, setError] = useState(false);
const reCaptchaKey = passedReCaptchaKey || process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY || null;
const src = passedSrc ||
getRecaptchaScriptSrc({ reCaptchaKey, language, useRecaptchaNet, useEnterprise }) ||
null;
// Reset state when script src is changed
const mounted = useRef(false);
useEffect(() => {
if (mounted.current) {
setLoaded(false);
setError(false);
}
mounted.current = true;
}, [src]);
// Handle script load
const onLoad = useCallback((e) => {
const grecaptcha = useEnterprise ? window?.grecaptcha?.enterprise : window?.grecaptcha;
if (grecaptcha) {
grecaptcha.ready(() => {
setGreCaptcha(grecaptcha);
setLoaded(true);
passedOnLoad?.(grecaptcha, e);
});
}
}, [passedOnLoad, useEnterprise]);
// Run 'onLoad' function once just in case if grecaptcha is already globally available in window
useEffect(() => onLoad(), [onLoad]);
// Handle script error
const onError = useCallback((e) => {
setError(true);
passedOnError?.(e);
}, [passedOnError]);
// Prevent unnecessary rerenders
const value = useMemo(() => ({ reCaptchaKey, grecaptcha, loaded, error }), [reCaptchaKey, grecaptcha, loaded, error]);
return (React.createElement(ReCaptchaContext.Provider, { value: value },
children,
React.createElement(Script, { id: id, src: src, strategy: strategy, onLoad: onLoad, onError: onError, ...props })));
};
export { ReCaptchaContext, ReCaptchaProvider, useReCaptchaContext };