React与Gatsby项目:如何按path.name重触发componentDidMount及script注入
解决Gatsby布局中根据路由重新注入TripAdvisor脚本的问题
你已经在布局组件的componentDidMount里成功实现了TripAdvisor脚本的首次注入,但因为Gatsby的布局组件通常是持久化挂载的——路由切换时不会卸载再重新挂载——所以componentDidMount只会触发一次。要实现根据path.name变化重新执行脚本注入,我们可以通过监听路由更新来触发逻辑,具体方案如下:
核心思路
- 把脚本注入逻辑抽成独立方法,方便复用
- 监听路由变化,当
path.name(Gatsby中对应location.pathname)改变时,重新执行注入逻辑 - 每次注入前先移除旧脚本,避免页面中存在多个相同脚本导致的重复渲染或控制台错误
类组件实现方案(适配你的现有代码)
因为你当前用的是类组件,我们可以用Gatsby提供的withRouter高阶组件,把路由信息注入到组件props中,然后在componentDidUpdate里判断路由是否变化:
首先导入withRouter:
import { withRouter } from 'gatsby';
然后修改你的布局组件:
class Layout extends React.Component { // 抽离脚本注入逻辑,方便重复调用 injectTripAdvisorScript = () => { // 先移除已存在的脚本,避免重复注入 const existingScript = document.getElementById('tripadvisor-left-script'); if (existingScript) { existingScript.remove(); } const tripadvisorLeft = document.createElement("script"); tripadvisorLeft.id = 'tripadvisor-left-script'; // 给脚本加唯一ID,方便后续定位移除 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); } componentDidMount() { // 页面首次加载时执行注入 this.injectTripAdvisorScript(); } componentDidUpdate(prevProps) { // 对比当前路由和上一次路由,判断是否需要重新注入 if (this.props.location.pathname !== prevProps.location.pathname) { this.injectTripAdvisorScript(); } } render() { // 你的布局渲染逻辑 return ( <div className="layout-container"> {this.props.children} </div> ); } } // 用withRouter包装组件,获取路由相关props export default withRouter(Layout);
函数组件实现方案(可选,后续重构参考)
如果之后打算把组件改成函数式写法,可以用useLocation钩子监听路由变化,配合useEffect实现:
import { useLocation } from 'gatsby'; import { useEffect } from 'react'; const Layout = ({ children }) => { const location = useLocation(); useEffect(() => { const injectScript = () => { // 清理旧脚本 const existingScript = document.getElementById('tripadvisor-left-script'); if (existingScript) existingScript.remove(); // 创建并注入新脚本 const tripadvisorLeft = document.createElement("script"); tripadvisorLeft.id = 'tripadvisor-left-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); }; injectScript(); // 组件卸载时清理脚本 return () => { const script = document.getElementById('tripadvisor-left-script'); if (script) script.remove(); }; }, [location.pathname]); // 依赖路由路径,路径变化时重新执行 return ( <div className="layout-container">{children}</div> ); }; export default Layout;
关键注意事项
- 必须清理旧脚本:如果不先移除旧脚本,路由切换后页面会存在多个相同的TripAdvisor脚本,可能导致组件重复渲染或控制台报错
- 路由监听的准确性:Gatsby中路由路径对应的是
location.pathname,如果你的业务中需要判断更细粒度的路由参数,可以调整判断逻辑 - 保持异步加载:脚本的
async=true属性要保留,避免阻塞页面渲染
内容的提问来源于stack exchange,提问作者Darren
相关产品推荐
相关产品推荐

