【问题标题】:React Router Link reloading page : Conflict with external eventReact Router Link重新加载页面:与外部事件冲突
【发布时间】:2021-01-04 13:52:33
【问题描述】:

我正在使用 React Router 的 Link 组件来处理我的应用中的页面转换。

我的应用包含在一个外部网页中,该网页有一些脚本(即 Google 跟踪代码管理器)在文档级别定义链接事件。

这会导致与链接事件发生冲突:点击链接时页面总是重新加载。

我试图通过 onClick 回调停止在我的 Link 组件上传播,但没有成功: <Link onClick={(e) => { e.stopPropagation(); }} [...]>...</Link>

我看到Link事件也是在document级别定义的,所以我不知道如何停止外部事件。

关于这个有什么线索吗?

谢谢!

【问题讨论】:

  • 你如何在外部网页中包含 React 应用程序?
  • 它包含在 script src 标签中的 javascript 脚本中

标签: javascript reactjs react-router google-tag-manager react-router-dom


【解决方案1】:

更新:如果不将整个应用程序呈现在 iframe 中,似乎没有简单的方法可以做到这一点。

如果你不介意这样做,那很容易(取自How to set iframe content of a react component):

const Frame = ({ children }) => {
    const [ref, setRef] = useState(null)
    const mountNode = ref?.contentWindow.document.body

    return (
        <iframe title="iframe" ref={setRef}>
            {mountNode && ReactDOM.createPortal(children, mountNode)}
        </iframe>
    )
}

然后,将您的主应用包装为 Frame 组件的子应用。在iframe 内的点击不会冒泡到父窗口,详见Capture click on div surrounding an iframe

这是一个 CodeSandbox demo 展示了这种方法。


下面的原始(无效)答案

在您的 AppRouter 组件上:

const blockClicks = useCallback((e) => {
    const { target } = e
    const { nodeName, href } = target
    if (
        target.closest('#root-id') &&
        nodeName === 'A' &&
        href &&
        (/^https?:\/\//.test(!href) ||
        href.startsWith(window.location.origin)
    )) {
        // amend logic specific to your use case
        // - we want to avoid blocking irrelevant clicks
        e.stopPropagation()
    }
})

useEffect(() => {
    document.addEventListener('click', blockClicks, true)

    return () =>
        document.removeEventListener('click', blockClicks, true)
})

【讨论】:

  • 感谢莱昂内尔的回答。 React 路由器在文档级别定义事件。因此,如果我停止传播我的点击,它就不会被我的路由器拦截。您的回答是否考虑到这一点?有没有办法让我的路由器在应用程序根级别而不是文档级别定义事件?
  • 显然不是,经过测试。我暂时把它留在这里,将尝试调整方法,如果无法挽救,稍后删除。
  • 会给你一些反馈。
  • 这不起作用。正如我所解释的,反应路由器事件和 GTM 事件似乎处于同一级别(文档)。所以停止传播没有效果。有没有办法在应用程序根级别而不是文档级别定义路由器事件?
  • 似乎不是。我假设它是由 ReactDOM 控制的,而不是 React Router,但我在任何地方都找不到它的记录。
【解决方案2】:

我在我的一个应用程序中遇到了非常相似的问题,我认为解决方案是尽可能避免使用react-router &lt;Link /&gt; component

我没有使用&lt;Link /&gt; 组件,而是使用react-router 提供的withRouter() HOC:

你写的:

Class MyComponent extends React.Component{
  <Link onClick={(e) => { e.stopPropagation(); }} [...]>
    ...
  </Link>
}

export default MyComponent;

可以替换为:

Class MyComponent extends React.Component{

  navigate = (event, location) => {
    event.preventDefault();
    this.props.history.push(location);
  }

  <a onClick={(e, href) => { this.navigate(e, href) }} [...]>
    ...
  </a>
}

export default withRouter(MyComponent);

这应该可以防止您的链接在文档级别捕获其他事件并达到与&lt;Link /&gt; 组件相同的结果。

【讨论】:

    猜你喜欢
    • 2017-11-15
    • 1970-01-01
    • 2020-04-29
    • 2021-03-18
    • 2018-01-13
    • 1970-01-01
    • 2016-08-29
    • 1970-01-01
    • 2018-03-30
    相关资源
    最近更新 更多