Next.js项目嵌入Clutch.co Widget遇渲染及Hydration失败问题求助
解决Next.js中嵌入Clutch.co Widget的渲染及Hydration失败问题
先明确你两个方案的核心问题:
方案一问题:
- 脚本未加载完成就渲染容器,Clutch初始化逻辑找不到目标元素
- 直接在
useEffect中设置setShowWidget(true),导致服务端与客户端渲染内容不匹配,触发Hydration失败 - 清理函数直接执行
removeChild可能触发DOM操作错误
方案二问题:
ClutchWidget组件没有return JSX元素,根本不会渲染任何内容
正确实现步骤
1. 编写客户端专属组件(避免SSR/SSG冲突)
创建带"use client"的组件,确保脚本加载完成后再渲染容器并触发初始化:
"use client"; import { useEffect, useState } from "react"; export default function ClutchWidget() { const [isScriptLoaded, setIsScriptLoaded] = useState(false); useEffect(() => { // 检查脚本是否已存在,避免重复注入 const existingScript = document.querySelector('script[src="https://widget.clutch.co/static/js/widget.js"]'); if (existingScript) { setIsScriptLoaded(true); window.clutchWidget?.init(); return; } const script = document.createElement("script"); script.src = "https://widget.clutch.co/static/js/widget.js"; script.async = true; // 脚本加载完成后再渲染容器并初始化 script.onload = () => { setIsScriptLoaded(true); window.clutchWidget?.init(); }; script.onerror = () => { console.error("Clutch Widget 脚本加载失败"); }; document.body.appendChild(script); // 安全清理脚本 return () => { if (script.parentNode) script.parentNode.removeChild(script); delete window.clutchWidget; }; }, []); // 仅在脚本加载完成后渲染容器,避免Hydration不匹配 return isScriptLoaded ? ( <div className="clutch-widget" data-url="https://widget.clutch.co" data-widget-type="3" data-height="320" data-nofollow="true" data-expandifr="true" data-scale="100" data-reviews="2220706,2123032,2113547" data-clutchcompany-id="2108125" /> ) : null; }
2. 在页面中正常引入组件
Page.js保持原有逻辑即可:
import ClutchWidget from "./components/Testimonials/ClutchWidget"; export default function Home() { return ( <div> <ClutchWidget /> </div> ); }
关键优化说明
- 避免重复加载:先检查DOM中是否已有目标脚本,防止多次注入
- 脚本加载后再渲染:确保Clutch初始化时能找到目标容器,同时避免服务端与客户端渲染内容不匹配(服务端返回
null,客户端仅在脚本就绪后渲染) - 手动触发初始化:处理脚本从缓存加载、容器后渲染的边界情况
- 安全清理:避免直接移除不存在的DOM元素导致报错
内容的提问来源于stack exchange,提问作者Mujahid Ali
相关产品推荐
相关产品推荐

