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

dangerouslySetInnerHTML在Gatsby/React页面中失效问题咨询

问题分析与解决方案

嘿,这个情况我太熟悉了!咱们先搞清楚为什么在Gatsby里脚本没反应,在Codepen却能跑通,再给你靠谱的解决办法。

为什么两种场景有差异?

Gatsby/React环境的核心限制

React的虚拟DOM机制和Gatsby的静态生成逻辑,是导致脚本失效的关键原因:

  • React默认不会执行通过dangerouslySetInnerHTML插入的<script>标签——它只负责把HTML字符串转换成DOM节点,为了性能和安全考量,跳过了脚本执行的步骤。
  • 如果你的Gatsby站点开启了SSR(服务器端渲染),脚本可能在服务器端就被插入,但服务器环境没有window这类浏览器全局对象,脚本执行时会静默报错,直接导致widget无法显示。
  • 就算是纯客户端渲染,脚本插入的时机可能早于依赖的DOM元素就绪,脚本找不到目标节点自然无法完成初始化。

Codepen/静态HTML的天然优势

在Codepen或者直接打开静态HTML时,浏览器是从头到尾完整解析整个文档:

  • 遇到<script>标签就会按规则执行(同步脚本立即运行,异步脚本加载完成后执行)。
  • 所有DOM元素和浏览器全局对象都已存在,脚本能顺利找到目标节点并完成初始化流程。

解决办法

方法1:手动提取并执行脚本

既然React不帮我们处理脚本执行,那我们自己来控制!用useRef和useEffect组合,在组件挂载后手动触发脚本执行:

import { useEffect, useRef } from 'react';

const PPHWidget = () => {
  const widgetContainer = useRef(null);
  // 替换成你的People per hour完整脚本HTML
  const pphHtml = `
    <div id="pph-widget" data-pph-account="你的账号ID"></div>
    <script type="text/javascript">
      (function(d, s, id) {
        var js, pjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) return;
        js = d.createElement(s); js.id = id;
        js.src = "https://widgets.peopleperhour.com/widget.js";
        pjs.parentNode.insertBefore(js, pjs);
      }(document, 'script', 'pph-widget-js'));
    </script>
  `;

  useEffect(() => {
    if (!widgetContainer.current) return;

    // 第一步:将HTML插入容器
    widgetContainer.current.innerHTML = pphHtml;

    // 第二步:提取脚本并手动执行
    const scripts = widgetContainer.current.querySelectorAll('script');
    scripts.forEach(oldScript => {
      const newScript = document.createElement('script');
      // 复制原脚本的属性与内容
      newScript.type = oldScript.type || 'text/javascript';
      if (oldScript.textContent) {
        newScript.textContent = oldScript.textContent;
      } else if (oldScript.src) {
        newScript.src = oldScript.src;
      }
      // 插入到body确保脚本执行
      document.body.appendChild(newScript);
      // 清理原脚本标签
      oldScript.remove();
    });
  }, []);

  return <div ref={widgetContainer} />;
};

export default PPHWidget;

方法2:用Gatsby插件优雅加载外部脚本

如果你的脚本是外部资源(比如示例中的https://widgets.peopleperhour.com/widget.js),可以用Gatsby插件简化流程:

  1. 安装插件:
npm install gatsby-plugin-load-script
  1. 在gatsby-config.js中配置:
module.exports = {
  plugins: [
    {
      resolve: 'gatsby-plugin-load-script',
      options: {
        src: 'https://widgets.peopleperhour.com/widget.js',
        loadAsync: true, // 异步加载避免阻塞页面
      },
    },
  ],
};
  1. 组件中只需渲染目标DOM节点即可:
const PPHWidget = () => {
  return <div id="pph-widget" data-pph-account="你的账号ID"></div>;
};

export default PPHWidget;

注意事项

  • 使用方法1时,务必确保脚本内容是可信的——dangerouslySetInnerHTML和手动执行脚本都存在XSS风险,不要插入未知来源的代码。
  • 部分第三方widget依赖特定全局变量,必要时可以监听脚本的load事件,确保脚本加载完成后再初始化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:24:16