Next.js中页面切换时<Script />标签无法加载,仅页面刷新才生效的问题求助
Next.js中页面切换时
标签无法加载,仅页面刷新才生效的问题求助return (<Script />)
各位大佬好,我最近在Next.js项目里碰到个头疼的问题,想请教下大家:
我做了个加载第三方祈祷时间小部件的组件,用了Next.js自带的<Script />标签。但发现用Next Link跳去别的页面再返回时,小部件根本没加载出来,反而直接显示了链接https://masjidbox.com/prayer-times/bpjm,只有手动刷新页面,小部件才会正常显示。
下面是我目前的组件代码(部分内容未写完):
"use client"; import { useRef } from "react"; import Script from "next/script"; const MasjidboxWidget: React.FC = () => { const widgetContainerRef = useRef<HTMLDivElement>(null); // 后续渲染逻辑省略 return ( <div ref={widgetContainerRef}> <Script src="https://masjidbox.com/widget/prayer-times/bpjm" /> </div> ); }; export default MasjidboxWidget;
问题原因
这是因为Next.js的客户端路由切换时,不会重新加载整个文档,而<Script />标签默认的加载策略不会在组件重新挂载时重新执行脚本,导致小部件无法再次初始化。
可行解决方案
方案1:用useEffect手动控制脚本加载卸载
既然是客户端组件,我们可以用useEffect在组件挂载时手动插入脚本,卸载时移除,这样每次组件回来都会重新加载脚本:
"use client"; import { useRef, useEffect } from "react"; const MasjidboxWidget: React.FC = () => { const widgetContainerRef = useRef<HTMLDivElement>(null); const scriptRef = useRef<HTMLScriptElement | null>(null); useEffect(() => { if (!widgetContainerRef.current) return; // 创建新的脚本元素 const script = document.createElement('script'); script.src = "https://masjidbox.com/widget/prayer-times/bpjm"; script.async = true; script.onload = () => { console.log("小部件脚本加载完成"); }; // 把脚本插到容器里 widgetContainerRef.current.appendChild(script); scriptRef.current = script; // 组件卸载时移除脚本,避免重复加载 return () => { if (scriptRef.current && widgetContainerRef.current) { widgetContainerRef.current.removeChild(scriptRef.current); scriptRef.current = null; } }; }, []); return <div ref={widgetContainerRef}></div>; }; export default MasjidboxWidget;
方案2:给Script标签加key强制重新渲染
利用Next.js的key机制,给<Script />标签加一个和当前路由绑定的key,这样路由变化(返回页面)时,key改变,Next.js会重新渲染这个脚本标签:
"use client"; import { useRef } from "react"; import Script from "next/script"; import { usePathname } from "next/navigation"; const MasjidboxWidget: React.FC = () => { const widgetContainerRef = useRef<HTMLDivElement>(null); const pathname = usePathname(); // 获取当前路由路径 return ( <div ref={widgetContainerRef}> <Script key={pathname} // 路由变了key就变,脚本重新加载 src="https://masjidbox.com/widget/prayer-times/bpjm" strategy="afterInteractive" onLoad={() => { // 如果小部件需要手动初始化,这里可以加初始化逻辑 }} /> </div> ); }; export default MasjidboxWidget;
额外提醒
如果第三方脚本本身会检测是否已加载过,就算重新插入也不执行的话,记得在清理函数里把脚本创建的全局变量或者DOM元素删掉,确保下次能重新初始化。也可以看看第三方小部件的文档,有没有提供手动初始化的API,那样会更靠谱。
内容来源于stack exchange
相关产品推荐
相关产品推荐

