切换React页面后外部JavaScript脚本无法运行求助
问题分析
当前问题的核心在于:
- 组件卸载时
useScript的清理函数会移除脚本,但浏览器会缓存该脚本,再次挂载组件时脚本不会重新执行,导致dw相关的初始化逻辑无法触发。 - 配置
dw的useEffect依赖为空数组,仅在组件首次挂载时执行,二次挂载时不会重新调用dw('settings')和dw('onPageChange')。 - 脚本加载与
dw调用的时机不匹配,可能出现dw调用时脚本尚未加载完成(二次挂载时)。
解决方案
1. 优化useScript Hook,跟踪脚本加载状态
修改useScript,让它返回脚本的加载状态,避免重复创建/移除脚本,同时确保脚本加载完成后再执行后续逻辑:
const useScript = (url) => { const [loaded, setLoaded] = useState(false); const [error, setError] = useState(null); useEffect(() => { // 检查脚本是否已存在于页面中 const existingScript = document.querySelector(`script[src="${url}"]`); if (existingScript) { // 如果脚本已存在,直接标记为加载完成 setLoaded(true); return; } const script = document.createElement('script'); script.src = url; script.async = true; const handleLoad = () => setLoaded(true); const handleError = (err) => setError(err); script.addEventListener('load', handleLoad); script.addEventListener('error', handleError); document.body.appendChild(script); return () => { script.removeEventListener('load', handleLoad); script.removeEventListener('error', handleError); // 不要移除脚本,避免二次加载时缓存问题;若必须移除,需同时清理window.dw // document.body.removeChild(script); // delete window.dw; // delete window.dw.q; }; }, [url]); return { loaded, error }; };
2. 调整Events组件,确保每次挂载都重新初始化dw
修改Events组件的useEffect,移除空依赖,改为在组件挂载且脚本加载完成后执行dw的配置逻辑:
function Events() { const { t } = useTranslation(); const { loaded } = useScript('https://resc.deskline.net/DW5/start/TERRBRENTA/api_code/index.js'); useEffect(() => { if (!loaded) return; // 每次挂载都重新初始化dw队列 window.dw = window.dw || function () { (window.dw.q = window.dw.q || []).push(arguments) }; window.dw('settings', api_code, { "context": {"targetRoute":["/eventi","/events","/veranstaltungen"]}, "lang": document.cookie.split('; ').find((row) => row.startsWith('i18next='))?.split('=')[1], "target": "tosc5container", "loadingAnimationColor": { "main": '#999999', "alt": '#B9E0AF' } }); window.dw('onPageChange', api_code); // 组件卸载时清空容器内容,避免残留 return () => { const container = document.getElementById('tosc5container'); if (container) container.innerHTML = ''; // 若需要完全重置dw,可添加: // window.dw.q = []; }; }, [loaded, api_code]); // 依赖添加loaded和api_code,确保状态变化时重新执行 return ( <section className="container pt-6 pb-6"> <Helmet> <title>{t('navbar.events')}</title> <meta name="description" content={t('pageDesc.events')} /> </Helmet> <h1 className="pb-2">{t('navbar.events')}</h1> <p className="pb-2">{t('evt')}</p> <div id="tosc5container" style={{ minHeight: "250px" }} /> </section> ); }
3. 额外优化:确保路由切换时的容器状态
由于React路由切换是SPA模式,组件卸载时容器#tosc5container的内容可能残留,导致二次挂载时脚本无法正确渲染,因此在组件卸载时清空容器内容(已包含在上述useEffect的清理函数中)。
关键说明
- 保留脚本在页面中不删除,利用浏览器缓存避免重复加载,同时确保二次挂载时脚本已存在,只需重新调用
dw的初始化逻辑即可。 - 将
loaded作为useEffect的依赖,确保只有脚本加载完成后才执行dw的配置,避免调用时机过早。 - 每次组件挂载都重新执行
dw的配置和onPageChange,确保容器能正确渲染内容。
内容的提问来源于stack exchange,提问作者ItServices
相关产品推荐
相关产品推荐

