Next.js 14.1(App Router)中Zendesk Widget导航后消失求助
Next.js 14.1 App Router中Zendesk Messaging Widget客户端导航后消失的解决方法
问题背景
在Next.js 14.1 App Router应用中集成Zendesk Messaging Widget时,页面初始加载时Widget按钮正常显示且可点击,但通过客户端导航(无全页刷新)后,Widget按钮和对应的iframe完全消失。尝试将组件放在layout.js中或单独页面引入,以及使用next/script加载脚本,问题均未解决。
原因分析
Next.js App Router的客户端导航会触发组件的卸载与重新挂载:
- 原代码中组件卸载时移除了Zendesk脚本,导致Widget依赖的全局对象
zE和DOM元素被清理; - Zendesk脚本首次加载后会缓存全局
zE对象,直接重新加载脚本不会触发初始化逻辑,因此导航后无法恢复Widget。
解决方案
方案1:保留脚本+路由变化时重新初始化
将组件转为客户端组件,移除脚本清理逻辑,监听路由变化,每次导航后检查zE对象是否存在,存在则重新显示Widget并执行用户登录逻辑,不存在则加载脚本。
'use client'; import { useEffect, useRef } from 'react'; import { usePathname } from 'next/navigation'; const ZendeskWidget = () => { const pathname = usePathname(); const isScriptLoaded = useRef(false); useEffect(() => { const initZendesk = () => { // 已有zE对象,直接重新初始化Widget if (window.zE) { window.zE('messenger', 'show'); window.zE("messenger", "loginUser", (callback) => { fetch('/api/zendesk') .then(res => res.json()) .then(jsonRes => { if (jsonRes.success) callback(jsonRes.token); }); }); return; } // 首次加载脚本 const script = document.createElement('script'); script.id = 'ze-snippet'; script.type = 'text/javascript'; script.src = `https://static.zdassets.com/ekr/snippet.js?key=${process.env.NEXT_PUBLIC_ZENDESK_KEY}`; script.async = true; script.onload = () => { window.zE("messenger", "loginUser", (callback) => { fetch('/api/zendesk') .then(res => res.json()) .then(jsonRes => { if (jsonRes.success) callback(jsonRes.token); }); }); isScriptLoaded.current = true; }; document.body.appendChild(script); }; initZendesk(); }, [pathname]); // 监听路由变化触发重新初始化 return null; }; export default ZendeskWidget;
方案2:使用Next.js Script组件+路由监听
利用Next.js的Script组件加载脚本,同时监听路由变化,导航后重新触发Widget初始化:
'use client'; import { useEffect } from 'react'; import { Script } from 'next/script'; import { usePathname } from 'next/navigation'; const ZendeskWidget = () => { const pathname = usePathname(); const initZendeskUser = () => { window.zE("messenger", "loginUser", (callback) => { fetch('/api/zendesk') .then(res => res.json()) .then(jsonRes => { if (jsonRes.success) callback(jsonRes.token); }); }); }; useEffect(() => { // 路由变化时,若zE已存在则重新显示并初始化用户 if (window.zE) { window.zE('messenger', 'show'); initZendeskUser(); } }, [pathname]); return ( <Script id="ze-snippet" type="text/javascript" src={`https://static.zdassets.com/ekr/snippet.js?key=${process.env.NEXT_PUBLIC_ZENDESK_KEY}`} onReady={initZendeskUser} strategy="lazyOnload" /> ); }; export default ZendeskWidget;
关键注意事项
- 必须添加
'use client'指令:App Router中组件默认是服务器组件,需转为客户端组件才能使用useEffect、usePathname等客户端API; - 不要移除Zendesk脚本:脚本卸载会导致Widget的DOM元素和全局状态丢失,后续无法快速恢复;
- 监听路由变化:客户端导航不会触发全页刷新,需通过
usePathname监听路由变更,主动触发Widget的重新初始化。
内容的提问来源于stack exchange,提问作者SteffenK
相关产品推荐
相关产品推荐

