如何解决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
相关产品推荐
相关产品推荐

