Reactjs React-`createPortal`和`document.body`一起导致立即触发click事件
我的应用程序有一个名为“打开模式”的按钮。单击此按钮时,将使用Reactjs React-`createPortal`和`document.body`一起导致立即触发click事件,reactjs,react-hooks,event-handling,event-propagation,react-portal,Reactjs,React Hooks,Event Handling,Event Propagation,React Portal,我的应用程序有一个名为“打开模式”的按钮。单击此按钮时,将使用createPortal将模式附加到文档.body 一旦安装了模式(即,isOpen===true),每次用户单击页面上的某个位置时,我都会向控制台打印一些文本 为此,如果isOpen===true,我将使用useffect钩子将单击事件绑定到document对象: useEffect(() => { const eventHandler = () => console.log("You clicked
createPortal
将模式附加到文档.body
一旦安装了模式(即,isOpen===true
),每次用户单击页面上的某个位置时,我都会向控制台打印一些文本
为此,如果isOpen===true
,我将使用useffect
钩子将单击事件绑定到document
对象:
useEffect(() => {
const eventHandler = () => console.log("You clicked me");
if (isOpen) {
document.addEventListener("click", eventHandler);
}
}, [isOpen]);
当用户第一次单击“打开模式”时,isOpen
从false
更改为true
,这会导致组件重新渲染。重新渲染完成后,将注册上述效果中的单击事件
问题
第一次单击“打开模式”会触发文档的单击事件(您可以在控制台中看到事件处理程序的输出)。这对我来说毫无意义-当第一次“打开模式”点击传播到文档上时,文档上的点击事件如何可能已经注册?
预期行为
第一次单击“打开模式”只会导致注册文档
的单击事件,此时不应触发事件本身
如果我省略了createPortal
(请参见演示的第38行),应用程序将按预期工作,即在第一次单击“打开模式”时注册事件,并在页面上所有后续单击时调用事件处理程序
如果我将modal挂载到应用程序根目录的同级,而不是document.body
(请参见演示的第39行),那么应用程序也可以正常工作。因此,上述问题仅在createPortal
与document.body
一起用作容器时才会出现,但我不明白原因。我不确定确切原因,但我认为,在传播完成时,由于事件传播而出现的问题,文档click
事件已注册,这可能是它调用eventHandler
的原因。如果我错了,请纠正我
如果停止事件传播,它工作正常
const openModal = useCallback(
function (e) {
if (!isOpen) { // stopping the propagation
e.stopPropagation();
}
setOpen(true);
},
[setOpen, isOpen]
);
演示链接谢谢@Naren。这很可能就是原因,尽管我不能完全理解到底发生了什么,希望有人能对此有更多的了解。为什么使用createPortal
似乎会“减慢”传播?尤其是在渲染完成后注册事件时?在没有createPortal
的情况下,该应用程序可以正常工作。这提供了一些见解,说明了为什么将createPortal
与document.body
一起使用是个坏主意。不过,我对本机事件和合成事件的了解还不够,无法解释我文章中的行为。将模式附加到应用程序根目录的同级,而不是document.body
works-。您是否选中了“是”,我在尝试使用createPortal
之前已经阅读过。如果您查看我上一篇评论中的演示,您将看到我在使用他们的想法,将模态附加到应用程序根目录的兄弟div,而不是document.body
本身(第39行)-这使一切都按预期工作。但我仍然不确定为什么将createPortal
与document.body
一起使用会扰乱传播。