React Router Link 正在重新加载页面:与外部事件冲突
React Router Link reloading page : Conflict with external event
我正在使用 React Router 的 Link 组件来处理我应用程序中的页面转换。
我的应用包含在一个外部网页中,该网页有一些脚本(即 Google 标签管理器)在文档级别定义 link 上的事件。
这会导致与 Link 事件发生冲突:单击 link 时页面总是重新加载。
我试图通过 onClick 回调停止我的 Link 组件的传播,但没有成功:
<Link onClick={(e) => { e.stopPropagation(); }} [...]>...</Link>
我看到 Link 事件也定义在 文档 级别,所以我不知道如何停止外部事件。
关于这个有什么线索吗?
谢谢!
更新: 似乎没有简单的方法可以做到这一点而不在 iframe
.
中渲染整个应用程序
如果您不介意这样做,那很简单(摘自 ):
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
内的点击不会冒泡到父级 window,详见 Capture click on div surrounding an iframe。
这里 CodeSandbox demo 展示了这种方法。
原始(non-functioning)答案如下
在您的 App
或 Router
组件上:
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-router <Link /> component
。
我没有使用 <Link />
组件,而是使用 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);
这应该可以防止您的 link 在文档级别捕获其他事件并获得与 <Link />
组件相同的结果。
我正在使用 React Router 的 Link 组件来处理我应用程序中的页面转换。
我的应用包含在一个外部网页中,该网页有一些脚本(即 Google 标签管理器)在文档级别定义 link 上的事件。
这会导致与 Link 事件发生冲突:单击 link 时页面总是重新加载。
我试图通过 onClick 回调停止我的 Link 组件的传播,但没有成功:
<Link onClick={(e) => { e.stopPropagation(); }} [...]>...</Link>
我看到 Link 事件也定义在 文档 级别,所以我不知道如何停止外部事件。
关于这个有什么线索吗?
谢谢!
更新: 似乎没有简单的方法可以做到这一点而不在 iframe
.
如果您不介意这样做,那很简单(摘自
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
内的点击不会冒泡到父级 window,详见 Capture click on div surrounding an iframe。
这里 CodeSandbox demo 展示了这种方法。
原始(non-functioning)答案如下
在您的 App
或 Router
组件上:
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-router <Link /> component
。
我没有使用 <Link />
组件,而是使用 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);
这应该可以防止您的 link 在文档级别捕获其他事件并获得与 <Link />
组件相同的结果。