UNPKG

next-recaptcha-v3

Version:

🤖 Next.js hook to add Google ReCaptcha to your application

62 lines (59 loc) • 2.76 kB
"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 };