Next.js 14中第三方Usercentrics脚本在路由切换时无法渲染内容的问题求助
嘿,我太懂这种糟心的问题了,给你捋捋原因和解决思路哈~
首先你的问题我完全get到:在Next.js14的根布局里加了Usercentrics的脚本,页面里放了div.uc-embed标签,刷新页面时这个div能正常加载出内容,但通过路由软切换(不用刷新的那种导航)进入页面时,这个div就是空的,只有刷新才会显示内容。
这其实是Next.js App Router的客户端导航机制导致的:软切换路由时不会重新加载整个页面,虽然Next.js确实保证脚本只加载一次,但Usercentrics的初始化逻辑大概率只在页面首次全量加载的时候运行一次,只会扫描当时DOM里的uc-embed元素。而路由切换后新渲染的uc-embed是后来才加入DOM的,脚本不会自动去识别并初始化它,所以就空着了。
给你几个亲测可行的解决方案,你可以按需试试:
方案1:监听路由变化,手动触发Usercentrics初始化
在包含uc-embed的页面组件里,用Next.js的路由钩子监听路由变化,每次路由切换到当前页面时,手动调用Usercentrics的初始化方法。
注意要给页面加上'use client'指令,因为用到了客户端钩子:
'use client'; import { useEffect } from 'react'; import { usePathname } from 'next/navigation'; export default function YourTargetPage() { const currentPath = usePathname(); useEffect(() => { // 检查Usercentrics的全局对象是否已加载 if (window.Usercentrics?.initEmbed) { // 找到页面里的uc-embed元素 const embedEl = document.querySelector('.uc-embed'); if (embedEl) { // 手动触发初始化,具体方法可以参考Usercentrics的文档,比如initEmbed或者专门的单元素渲染方法 window.Usercentrics.initEmbed(); // 要是有针对单个元素的方法,也可以用这个,比如: // window.Usercentrics.renderEmbed(embedEl); } } }, [currentPath]); // 路由变化时重新执行初始化 return ( <div className="uc-embed" uc-layout="1" uc-data="all"></div> ); }
方案2:通过Context共享初始化方法(多页面复用场景)
如果多个页面都用到uc-embed,可以把初始化函数通过React Context共享,这样每个需要的组件都能直接调用:
首先在根布局里配置:
// app/layout.js import { Script } from 'next/script'; import { createContext, useState } from 'react'; export const UsercentricsContext = createContext(null); export default function RootLayout({ children }) { const [usercentricsInit, setUsercentricsInit] = useState(null); return ( <html lang="en"> <UsercentricsContext.Provider value={usercentricsInit}> <body> {children} <Script src="Usercentrics官方加载脚本路径" // 替换为实际的脚本路径即可 onLoad={() => { // 脚本加载完成后,保存初始化方法 if (window.Usercentrics?.initEmbed) { setUsercentricsInit(window.Usercentrics.initEmbed); // 首次初始化页面上的元素 window.Usercentrics.initEmbed(); } }} /> </body> </UsercentricsContext.Provider> </html> ); }
然后在需要的页面组件里使用:
'use client'; import { useEffect, useContext } from 'react'; import { usePathname } from 'next/navigation'; import { UsercentricsContext } from '../layout'; export default function YourTargetPage() { const currentPath = usePathname(); const initUsercentrics = useContext(UsercentricsContext); useEffect(() => { if (initUsercentrics) { initUsercentrics(); } }, [currentPath, initUsercentrics]); return ( <div className="uc-embed" uc-layout="1" uc-data="all"></div> ); }
方案3:组件挂载时直接初始化(单页面场景)
如果只有单个页面用到这个嵌入组件,也可以直接在组件挂载时触发初始化:
'use client'; import { useEffect } from 'react'; export default function YourTargetPage() { useEffect(() => { const initEmbed = () => { if (window.Usercentrics?.initEmbed) { window.Usercentrics.initEmbed(); } }; // 组件挂载完成后立即执行初始化 initEmbed(); }, []); return ( <div className="uc-embed" uc-layout="1" uc-data="all"></div> ); }
另外补充下,Next.js的Script组件你可以根据需求调整加载策略,比如lazyOnload或者afterInteractive,但核心问题还是路由切换后的元素初始化,所以上面的手动触发逻辑才是关键。
备注:内容来源于stack exchange,提问作者Bahman Parsa Manesh

