ReactJS中使用<Link>时外部脚本失效问题
解决React中使用跳转后外部脚本失效的问题
这个问题我之前也碰到过,本质是React单页应用的客户端路由特性导致的:用React Router的<Link>跳转时,页面不会完全刷新,主布局的componentDidMount只在应用首次加载时触发一次。当你跳转到其他页面再返回时,主布局并没有被卸载和重新挂载,所以脚本加载逻辑不会再次执行,外部脚本(比如你这里的TripAdvisor组件)自然没法正常工作。
下面给你几个可行的解决方案:
方案1:将脚本加载逻辑移到目标组件中
把脚本的加载和清理逻辑,放到需要显示TripAdvisor内容的组件里,而不是主布局。这样每次组件挂载时都会加载脚本,卸载时清理避免重复:
类组件示例
class TripAdvisorSection extends React.Component { componentDidMount() { // 创建并加载脚本 const tripadvisorScript = document.createElement("script"); tripadvisorScript.src = "https://www.jscache.com/wejs?wtype=selfserveprop&uniq=789&locationId=10467767&lang=en_NZ&rating=true&nreviews=0&writereviewlink=true&popIdx=true&iswide=true&border=false&display_version=2"; tripadvisorScript.async = true; // 挂载到指定容器(确保组件render里有这个容器) document.getElementById('tripadvisor-container').appendChild(tripadvisorScript); } componentWillUnmount() { // 清理旧脚本和生成的DOM元素 const existingScript = document.querySelector('script[src="https://www.jscache.com/wejs?wtype=selfserveprop&uniq=789&locationId=10467767&lang=en_NZ&rating=true&nreviews=0&writereviewlink=true&popIdx=true&iswide=true&border=false&display_version=2"]'); if (existingScript) existingScript.remove(); // 移除TripAdvisor生成的元素 const taElements = document.querySelectorAll('.ta-selfserve-prop'); taElements.forEach(el => el.remove()); } render() { return <div id="tripadvisor-container"></div>; } }
函数组件(useEffect)示例
import { useEffect } from 'react'; function TripAdvisorSection() { useEffect(() => { // 创建脚本 const tripadvisorScript = document.createElement("script"); tripadvisorScript.src = "https://www.jscache.com/wejs?wtype=selfserveprop&uniq=789&locationId=10467767&lang=en_NZ&rating=true&nreviews=0&writereviewlink=true&popIdx=true&iswide=true&border=false&display_version=2"; tripadvisorScript.async = true; const container = document.getElementById('tripadvisor-container'); container.appendChild(tripadvisorScript); // 清理函数:组件卸载时执行 return () => { const existingScript = document.querySelector('script[src="https://www.jscache.com/wejs?wtype=selfserveprop&uniq=789&locationId=10467767&lang=en_NZ&rating=true&nreviews=0&writereviewlink=true&popIdx=true&iswide=true&border=false&display_version=2"]'); if (existingScript) existingScript.remove(); // 清理TripAdvisor生成的DOM const taElements = container.querySelectorAll('.ta-selfserve-prop'); taElements.forEach(el => el.remove()); }; }, []); // 空依赖数组确保只在挂载时执行一次 return <div id="tripadvisor-container"></div>; }
方案2:监听路由变化,全局重新加载脚本
如果这个脚本需要在多个页面显示,你可以在主布局里监听React Router的路由变化,每次路由切换时重新加载脚本:
import { useEffect } from 'react'; import { useLocation, Outlet } from 'react-router-dom'; function MainLayout() { const location = useLocation(); useEffect(() => { // 先清理旧脚本和DOM const existingScript = document.querySelector('script[src="https://www.jscache.com/wejs?wtype=selfserveprop&uniq=789&locationId=10467767&lang=en_NZ&rating=true&nreviews=0&writereviewlink=true&popIdx=true&iswide=true&border=false&display_version=2"]'); if (existingScript) existingScript.remove(); const taElements = document.querySelectorAll('.ta-selfserve-prop'); taElements.forEach(el => el.remove()); // 加载新脚本 const tripadvisorLeft = document.createElement("script"); tripadvisorLeft.src = "https://www.jscache.com/wejs?wtype=selfserveprop&uniq=789&locationId=10467767&lang=en_NZ&rating=true&nreviews=0&writereviewlink=true&popIdx=true&iswide=true&border=false&display_version=2"; tripadvisorLeft.async = true; document.body.appendChild(tripadvisorLeft); }, [location.pathname]); // 路由path变化时触发 return ( <div className="layout"> {/* 你的导航栏等布局内容 */} <Outlet /> {/* 渲染当前路由对应的组件 */} </div> ); }
关键注意点
- 一定要清理旧的脚本和生成的DOM元素,否则会出现重复加载、元素叠加的问题。
- 外部脚本的
async属性可以保留,但如果脚本依赖DOM元素存在,确保容器元素已经渲染完成再加载脚本(比如在componentDidMount或useEffect里执行,此时组件已经挂载到DOM)。
内容的提问来源于stack exchange,提问作者Darren
相关产品推荐
相关产品推荐

