Goal: I want to implement a popover(modal) in React. When the user click a button, then the popover is open. Close the popover when the user clicks outside of the popover.
Logic: conditionally render the popover component using state. In popover component, add event listener which listen to the click event of the document. If a user clicks a document, it changes the state to false to not render popover component.
Problem: If I click the button to open the popover, event listener triggered. So that the popover closes automatically.
I want to know why this is happening.
import { useState } from "react";
import Popover from "./Popover";
const TaskButton = () => {
const [isPopoverShown, setIsPopoverShown] = useState(false);
const popoverOpenHandler = () => {
setIsPopoverShown(true);
};
const popoverCloseHandler = () => {
setIsPopoverShown(false);
};
return (
<div>
<button
onClick={popoverOpenHandler}
>
button
</button>
{isPopoverShown && (
<Popover isOpen={isPopoverShown} onClose={popoverCloseHandler}>
hello
</Popover>
)}
</div>
);
};
export default TaskButton;
import React, { useEffect, useRef } from "react";
const Popover =({ onClose, children }) => {
const popoverRef = useRef(null);
useEffect(() => {
const pageClickEvent = (event) => {
if (popoverRef.current !== event.target) {
onClose();
}
};
document.addEventListener("click", pageClickEvent);
return () => {
document.removeEventListener("click", pageClickEvent);
};
}, [onClose]);
return <div ref={popoverRef}>{children}</div>;
}
export default Popover;
My thought:
I think the problem is coming from event bubbling and capturing.
document.addEventListener("mousedown", pageClickEvent);
document.addEventListener("click", pageClickEvent, true);
Because when I change the code one of these, it works how I expected.
But I want to know why it works if I change the event 'click' to 'mousedown'(or up). Or if I change the capture option to true.
I think the event listener is activated only when the component is mounted on DOM. Therefore, the event listener should not be triggered by clicking the button to open the component itself.