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

如何解决Gatsby项目中react-google-recaptcha-v3脚本重复加载问题

解决Gatsby中react-google-recaptcha-v3脚本重复加载的问题

我在Gatsby项目中已成功安装react-google-recaptcha-v3,功能运行正常,但遇到了Recaptcha脚本多次加载的问题。当前gatsby-ssr.js和gatsby-browser.js代码如下:

import React from "react"
import { PageContextProvider } from "./src/providers/page_context"
import { GoogleReCaptchaProvider } from "react-google-recaptcha-v3"

export const wrapPageElement = ({ element, props }) => (
  <main>
    <GoogleReCaptchaProvider reCaptchaKey={process.env.RECAPTCHA_V3_SITE_KEY}>
      <PageContextProvider {...props}>{element}</PageContextProvider>
    </GoogleReCaptchaProvider>
  </main>
)

使用Recaptcha V3的组件代码示例:

const MyComponent = ({ data, ...props }) => {
  const { executeRecaptcha } = useGoogleReCaptcha()

  const verifyRecaptcha = useCallback(async () => {
    if (!executeRecaptcha) {
      console.log("Execute recaptcha not yet available")
      return
    }
    return await executeRecaptcha("")
  }, [executeRecaptcha])

  useEffect(() => {
    verifyRecaptcha()
  }, [verifyRecaptcha])

  return (
    <div>
      <button onClick={async ()=>{
        const recaptcha_token = await verifyRecaptcha()
        // Do something..
      }}></button>
    </div>
  )
}

使用版本:

  • node = v18.15.0
  • Gatsby = v5.13.7
  • react-google-recaptcha-v3 = v1.10.1

问题根源

Gatsby的wrapPageElement会在每次页面路由切换时触发渲染,导致GoogleReCaptchaProvider被重复实例化,进而重复加载Recaptcha的外部脚本。

解决办法

1. 改用wrapRootElement挂载Provider(优先方案)

wrapRootElement只会在应用初始化时执行一次,不会随页面切换重复触发,把GoogleReCaptchaProvider移到这里就能从根本上解决重复加载问题。

修改后的gatsby-ssr.js和gatsby-browser.js代码:

import React from "react"
import { PageContextProvider } from "./src/providers/page_context"
import { GoogleReCaptchaProvider } from "react-google-recaptcha-v3"

// 全局只挂载一次Recaptcha Provider
export const wrapRootElement = ({ element }) => (
  <GoogleReCaptchaProvider reCaptchaKey={process.env.RECAPTCHA_V3_SITE_KEY}>
    {element}
  </GoogleReCaptchaProvider>
)

// 保留原有的wrapPageElement处理PageContextProvider
export const wrapPageElement = ({ element, props }) => (
  <main>
    <PageContextProvider {...props}>{element}</PageContextProvider>
  </main>
)

2. 给Provider添加脚本加载控制(备选方案)

如果必须使用wrapPageElement,可以通过scriptProps配置脚本加载逻辑,利用全局变量判断脚本是否已加载:

<GoogleReCaptchaProvider
  reCaptchaKey={process.env.RECAPTCHA_V3_SITE_KEY}
  scriptProps={{
    async: false,
    defer: true,
    appendTo: "head",
    // 检查全局变量,避免重复加载
    onLoad: () => {
      if (window.grecaptcha) {
        console.log("Recaptcha脚本已加载,无需重复加载")
      }
    }
  }}
>
  <PageContextProvider {...props}>{element}</PageContextProvider>
</GoogleReCaptchaProvider>

不过这个方案不如第一种彻底,仅作为特殊场景下的备选。

3. 检查组件内调用逻辑

当前组件中useEffect和按钮点击调用verifyRecaptcha属于正常业务逻辑,不会导致脚本重复加载,核心问题仍在Provider的重复渲染上。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 13:23:20