You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React模块化项目中整合Google Recaptcha的脚本加载方案咨询

我之前在React模块化项目里整合Google reCAPTCHA的时候,刚好踩过类似的坑,给你分享几个适配模块化架构的封装方案,亲测好用:

方案一:动态Script加载工具函数(基础版)

先封装一个通用的动态加载脚本工具,这样不仅能用来加载reCAPTCHA,其他需要动态引入的脚本也能复用。

// utils/loadScript.js
export const loadScript = (url, callback) => {
  // 先检查脚本是否已经存在,避免重复加载
  if (document.querySelector(`script[src="${url}"]`)) {
    callback?.();
    return;
  }

  const script = document.createElement('script');
  script.src = url;
  script.async = true;
  script.defer = true;

  // 加载成功回调
  script.onload = () => {
    callback?.();
  };

  // 加载失败处理
  script.onerror = (error) => {
    console.error('脚本加载失败:', error);
  };

  document.body.appendChild(script);
};

然后在你的React组件里这样用:

import { useEffect, useState } from 'react';
import { loadScript } from '../utils/loadScript';

const RecaptchaComponent = () => {
  const [isRecaptchaReady, setIsRecaptchaReady] = useState(false);

  useEffect(() => {
    // 定义Google脚本需要的全局回调函数
    window.onloadCallback = () => {
      setIsRecaptchaReady(true);
      // 这里可以初始化reCAPTCHA实例
    };

    // 加载reCAPTCHA脚本
    loadScript(
      'https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit',
      () => console.log('reCAPTCHA脚本加载完成')
    );

    // 组件卸载时清理全局回调,避免内存泄漏
    return () => {
      delete window.onloadCallback;
    };
  }, []);

  return (
    <div>
      {isRecaptchaReady ? (
        <div id="recaptcha-box"></div>
      ) : (
        <p>reCAPTCHA加载中...</p>
      )}
    </div>
  );
};

export default RecaptchaComponent;

方案二:自定义Hook封装(React化复用方案)

如果你的项目里多个组件都需要用到reCAPTCHA,用自定义Hook封装会更符合React的组件化思想,复用性更强:

// hooks/useRecaptcha.js
import { useEffect, useState } from 'react';

export const useRecaptcha = () => {
  const [isLoaded, setIsLoaded] = useState(false);
  const [loadError, setLoadError] = useState(null);

  useEffect(() => {
    const recaptchaUrl = 'https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit';
    
    // 如果已经加载过grecaptcha,直接标记为就绪
    if (window.grecaptcha) {
      setIsLoaded(true);
      return;
    }

    // 定义全局回调
    window.onloadCallback = () => {
      setIsLoaded(true);
    };

    const script = document.createElement('script');
    script.src = recaptchaUrl;
    script.async = true;
    script.defer = true;

    script.onload = () => console.log('reCAPTCHA脚本加载成功');
    script.onerror = (err) => {
      setLoadError('reCAPTCHA加载失败,请稍后重试');
      console.error(err);
    };

    document.body.appendChild(script);

    // 清理函数
    return () => {
      delete window.onloadCallback;
    };
  }, []);

  return {
    isLoaded,
    loadError,
    grecaptcha: window.grecaptcha
  };
};

组件中使用这个Hook:

import { useEffect, useRef } from 'react';
import { useRecaptcha } from '../hooks/useRecaptcha';

const LoginForm = () => {
  const { isLoaded, loadError, grecaptcha } = useRecaptcha();
  const recaptchaRef = useRef(null);

  useEffect(() => {
    if (isLoaded && recaptchaRef.current) {
      // 渲染reCAPTCHA
      grecaptcha.render(recaptchaRef.current, {
        sitekey: process.env.REACT_APP_RECAPTCHA_SITE_KEY, // 建议用环境变量存密钥
        callback: (token) => {
          console.log('验证通过,token:', token);
          // 这里处理表单提交逻辑,比如把token传给后端验证
        }
      });
    }
  }, [isLoaded, grecaptcha]);

  if (loadError) return <p className="error">{loadError}</p>;
  if (!isLoaded) return <p>加载中...</p>;

  return (
    <form>
      <input type="email" placeholder="邮箱" />
      <input type="password" placeholder="密码" />
      {/* 挂载reCAPTCHA的容器 */}
      <div ref={recaptchaRef}></div>
      <button type="submit">登录</button>
    </form>
  );
};

export default LoginForm;

几个关键注意事项

  • 全局回调必须挂在window上:Google的reCAPTCHA脚本会全局查找onloadCallback函数,所以必须把它挂载到window对象上,组件卸载时记得清理,避免内存泄漏。
  • 避免重复加载:每次加载前先检查脚本是否已经存在,或者检查window.grecaptcha是否已定义,防止多次插入script标签。
  • 环境变量存密钥:不要把reCAPTCHA的站点密钥硬编码在代码里,存在环境变量(比如.env文件)更安全。
  • SSR项目适配:如果你的项目是服务端渲染(比如Next.js),要确保脚本只在客户端加载,可以用typeof window !== 'undefined'判断环境,或者用框架提供的客户端加载方案。

内容的提问来源于stack exchange,提问作者JavaHead

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:46:48