joh*_*pin 5 javascript reactjs react-hooks
我使用 React hooks 创建一个应用程序。我有一个辅助函数,当您单击提供使用的组件外部时,该函数onClickOutsideHook(ref, callback)会触发:callbackrefReact.useRef
export const onClickOutsideHook = (ref, callback) => {
// Hook get from https://stackoverflow.com/a/42234988/8583669
React.useEffect(() => {
const handleClickOutside = event => {
if (ref?.current && !ref.current.contains(event.target)) {
callback();
}
};
// Bind the event listener
document.addEventListener("mousedown", handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener("mousedown", handleClickOutside);
};
}, [callback, ref]);
};
Run Code Online (Sandbox Code Playgroud)
我有一个Dropdown使用此帮助程序的组件,因此当您在其外部单击时它会关闭。该组件有一个Modal使用 的子组件ReactDOM.createPortal。我用它来渲染, Modal以便body它可以覆盖所有应用程序屏幕。我的Modal包含一个按钮,当您单击它时会发出警报消息:
function Modal() {
return ReactDOM.createPortal(
<div
style={{
position: "absolute",
top: 0,
left: 0,
height: "100%",
width: "100%",
background: "rgba(0,0,0,0.6)"
}}
>
<button onClick={() => alert("Clicked on Modal")}>Click</button>
</div>,
document.body
);
}
function Dropdown(props) {
const [isModalOpen, setIsModalOpen] = React.useState(false);
const dropdownRef = React.useRef(null);
onClickOutsideHook(dropdownRef, props.onClose);
return (
<div ref={dropdownRef}>
Click outside and I will close
<button onClick={() => setIsModalOpen(true)}>open Modal</button>
{isModalOpen ? <Modal /> : <></>}
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
问题是,当我单击Modal按钮触发警报时,该按钮Dropdown之前已关闭,因为我在其外部单击(Modal不渲染为 的子项,Dropdown而是渲染为body)。所以我的警报永远不会被触发。
有没有一种方法可以定义为usingModal的子级,但仍然在using中渲染它?DropdownrefbodyReactDOM.createPortal
只需查看CodeSandbox即可。
就像门户文档所说:
尽管门户可以位于 DOM 树中的任何位置,但它在其他方面的行为都像普通的 React 子级......
这包括事件冒泡。从门户内部触发的事件将传播到包含 React 树中的祖先,即使这些元素不是 DOM 树中的祖先。
但这里不是这样,mousedown事件监听器被添加到文档上,而不仅仅是Dropdown组件。即便如此,冒泡现象仍然发生。
这意味着,如果您向Modal添加引用,然后在mousedown事件上添加事件侦听器,其全部目的是停止传播,则永远不会调用handleClickOutside函数。
这似乎仍然是一种解决方法,我不知道是否有适当的方法来检查。
function Modal() {
const modalRef = useRef();
useEffect(() => {
const stopPropagation = e => {
e.stopPropagation();
};
const { current: modalDom } = modalRef;
modalDom.addEventListener("mousedown", stopPropagation);
return () => {
modalDom.removeEventListener("mousedown", stopPropagation);
};
}, []);
return ReactDOM.createPortal(
<div
ref={modalRef}
style={{
position: "absolute",
top: 0,
left: 0,
height: "100%",
width: "100%",
background: "rgba(0,0,0,0.6)"
}}
>
<button onClick={() => alert("Clicked on Modal")}>Click</button>
</div>,
document.body
);
}
Run Code Online (Sandbox Code Playgroud)
从以下CodeSandbox中观察 Modal 组件。
| 归档时间: |
|
| 查看次数: |
6890 次 |
| 最近记录: |