我正在使用Material-UI ClickAwayListener组件和使用react-router的现有代码。该按钮位于<ClickAwayListener> ... </ClickAwayListener>
之外,因此我希望onClickAway
在导航至其他路线之前会触发。但这不是
下面是我的代码的复制品,在某种程度上证明了我的意思
function Component(){
const handleClickAway = () => {
// Do something here
}
return (
<>
<button>
<Link to="/other-route">Click here </Link>
</button>
// Some other element here
<ClickAwayListener onClickAway={handleClickAway}>
<div>
// Content
</div>
</ClickAwayListener>
</>
)
}
因此,如果我单击
<ClickAwayListener>
和<button>
之外的任何位置,则会触发handleClickAway
,但是如果我单击包含与其他路线相似的<button>
,则不会。我尝试查看
ClickAwayListener
的源代码,我相信此part负责检测点击 React.useEffect(() => {
if (mouseEvent !== false) {
const mappedMouseEvent = mapEventPropToEvent(mouseEvent);
const doc = ownerDocument(nodeRef.current);
doc.addEventListener(mappedMouseEvent, handleClickAway);
return () => {
doc.removeEventListener(mappedMouseEvent, handleClickAway);
};
}
return undefined;
}, [handleClickAway, mouseEvent]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
据我所知,这部分将在组件安装/重新渲染时首先添加一个事件侦听器以单击事件,并将在组件卸载之前删除该侦听器(
useEffect()
的默认行为)。但是,如果是这种情况,那么在涉及到在ClickAwayListener
区域之外单击的任何事件导致组件卸载之前,应触发onClickAway
侦听器,因为该侦听器仍会附加到click事件。简而言之,这是我期望的行为:
单击按钮->
onClickAway
fire->组件卸载->转到新路径->运行useEffect()的清理代码->删除监听器但这是到目前为止发生的事情
单击按钮->组件获取卸载->转到新路径->运行useEffect()的清理代码->删除侦听器
有人可以帮我解释为什么会这样吗?
最佳答案
ClickAwayListener
组件通过将事件侦听器附加到 document
来工作,当触发鼠标事件时,仅当鼠标事件不在元素内时才触发onClickAway
。Link
中的 react-router-dom
组件本质上是这样呈现的:
<a onClick={() => navigate()}>click</a>
当您单击链接并调用
navigate()
时,React会卸载当前组件,并在下一帧中安装下一页组件。但问题是,仅在下一次重新渲染之后才处理处理程序,此时,由于document
的事件处理程序已被卸载,因此该事件处理程序已被删除,因此未调用任何内容。通过等待直到下一次重新渲染之后,才调用
ClickAwayListener
的处理程序,可以解决该问题。<button
onClick={() => {
setTimeout(() => {
history.push("/2");
});
}}
>
现场演示关于javascript - 单击链接/按钮导航到其他路线时,不会触发ClickAwayListener,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/64531264/