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

使用dangerouslySetInnerHTML渲染脚本出现Hydration错误求助

问题描述

没法让ImageMapPro脚本正常运行,只能靠dangerouslySetInnerHTML才能让插件在前端显示,不然控制台会报ImageMapPro未定义。但插件正常显示一秒后,控制台弹出Hydration错误:

app-index.js:31 Warning: Prop dangerouslySetInnerHTML did not match. Server: "\n <div id="image-map-pro" data-image-map-id="5256f3ec...\n

相关代码

ImageMap.jsx

'use client'
import { useEffect, useState } from "react";

export default function ImageMapPro() {
  const [render, setRender] = useState(false);
  const script = `
  <div id="image-map-pro"></div>
  <script src="image-map-pro/image-map-pro.min.js"></script>
  <script>ImageMapPro.init('#image-map-pro', {"id":"5256f3ec-3b42-4614-bd33-7332a713cac7","artboards":[{"children":[{"id":"27b1e6ba-0de4-49a0-a732-0d6824f84d17","title":"Ellipse","type":"oval","x":9.433962264150944,"y":32.239583333333336,"width":50.35377358490566,"height":54.583333333333336,"default_style":{"background_color":"#ff0000"},"x_image_background":9.433962264150944,"y_image_background":32.239583333333336},{"id":"1e6ab53b-a4c2-4a2f-a2fd-6fa8df37c642","title":"Rect","type":"rect","x":22.995283018867923,"y":18.90625,"width":61.910377358490564,"height":55,"tooltip_content":[{"type":"Heading","text":"test","heading":"h3","other":{"id":"","classes":"","css":""},"style":{"fontFamily":"sans-serif","fontSize":20.8,"lineHeight":"normal","color":"#ffffff","textAlign":"left"},"boxModel":{"width":"auto","height":"auto","margin":{"top":0,"bottom":0,"left":0,"right":0},"padding":{"top":10,"bottom":10,"left":10,"right":10}},"id":"ffbed5ee-255b-41a6-8229-c3f6f693497b"}],"x_image_background":22.995283018867923,"y_image_background":18.90625}]}],"version":"6.0.8","general":{"name":"Untitled"}})</script>
  `
  useEffect(() => {
    setRender(true);
  }, []);

  return (
    <div dangerouslySetInnerHTML={{ __html: script }}></div>
  );
}

page.jsx

return (
    <>
        <ImageMapPro />
    </>
 );
问题原因

Hydration错误本质是服务端渲染出的HTML和客户端 hydration 后的HTML不一致。你用dangerouslySetInnerHTML插入内容时,服务端只会渲染初始的<div id="image-map-pro"></div>,但客户端执行脚本后,ImageMapPro会修改这个div(比如添加data-image-map-id属性),导致前后内容不匹配,触发警告。

修复方案

方案1:控制组件仅在客户端渲染

既然已经加了'use client',直接用render状态控制组件只在客户端渲染,服务端返回空内容,避免前后差异:
修改ImageMap.jsx的return部分:

return render ? (
  <div dangerouslySetInnerHTML={{ __html: script }}></div>
) : null;

这样服务端不会渲染任何插件相关内容,客户端触发useEffect后才加载,不会有Hydration不匹配问题。

方案2:手动操作DOM替代dangerouslySetInnerHTML

直接用React的DOM API创建元素和加载脚本,更安全,也彻底避免Hydration问题:

'use client'
import { useEffect, useRef } from "react";

export default function ImageMapPro() {
  const containerRef = useRef(null);

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

    // 创建插件容器
    const mapDiv = document.createElement('div');
    mapDiv.id = 'image-map-pro';
    containerRef.current.appendChild(mapDiv);

    // 加载插件脚本
    const script = document.createElement('script');
    script.src = 'image-map-pro/image-map-pro.min.js';
    script.onload = () => {
      // 脚本加载完成后初始化插件
      ImageMapPro.init('#image-map-pro', {
        "id":"5256f3ec-3b42-4614-bd33-7332a713cac7",
        "artboards":[{"children":[{"id":"27b1e6ba-0de4-49a0-a732-0d6824f84d17","title":"Ellipse","type":"oval","x":9.433962264150944,"y":32.239583333333336,"width":50.35377358490566,"height":54.583333333333336,"default_style":{"background_color":"#ff0000"},"x_image_background":9.433962264150944,"y_image_background":32.239583333333336},{"id":"1e6ab53b-a4c2-4a2f-a2fd-6fa8df37c642","title":"Rect","type":"rect","x":22.995283018867923,"y":18.90625,"width":61.910377358490564,"height":55,"tooltip_content":[{"type":"Heading","text":"test","heading":"h3","other":{"id":"","classes":"","css":""},"style":{"fontFamily":"sans-serif","fontSize":20.8,"lineHeight":"normal","color":"#ffffff","textAlign":"left"},"boxModel":{"width":"auto","height":"auto","margin":{"top":0,"bottom":0,"left":0,"right":0},"padding":{"top":10,"bottom":10,"left":10,"right":10}},"id":"ffbed5ee-255b-41a6-8229-c3f6f693497b"}],"x_image_background":22.995283018867923,"y_image_background":18.90625}]}],
        "version":"6.0.8",
        "general":{"name":"Untitled"}
      });
    };
    document.body.appendChild(script);

    // 组件卸载时清理资源
    return () => {
      containerRef.current.innerHTML = '';
      script.remove();
      // 如果插件提供了销毁方法,这里可以调用,比如:ImageMapPro.destroy('#image-map-pro');
    };
  }, []);

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

这种方式完全在客户端执行DOM操作,服务端不会渲染任何插件相关内容,从根源上解决Hydration不匹配问题,同时比dangerouslySetInnerHTML更安全,降低XSS风险。

额外提示

  • 确认image-map-pro.min.js的路径正确,客户端能正常访问到该文件。
  • 如果ImageMapPro有官方React集成包,优先使用官方方案,避免手动操作DOM。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 06:15:02