We have a menu. If menu is open, We should be able to close it by clicking anywhere:
class Menu extends Component {
componentWillMount() {
document.addEventListener("click", this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener("click", this.handleClickOutside);
}
openModal = () => {
this.props.showModal();
};
handleClickOutside = ({ target }) => {
const { displayMenu, toggleMenu, displayModal } = this.props;
if (displayMenu) {
if (displayModal || this.node.contains(target)) {
return;
}
toggleMenu();
}
};
render() {
return (
<section ref={node => (this.node = node)}>
<p>
<button onClick={this.openModal}>open modal</button>
</p>
<p>
<button onClick={this.openModal}>open modal</button>
</p>
<p>
<button onClick={this.openModal}>open modal</button>
</p>
</section>
);
}
}
From menu, we can open a modal by clicking on button inside menu. We can close modal in two ways: by clicking close modal button inside modal, or on click on bakcdrop/overlay outside the modal:
class Modal extends Component {
hideModal = () => {
this.props.hideModal();
};
onOverlayClick = ({ target, currentTarget }) => {
if (target === currentTarget) {
this.hideModal();
}
};
render() {
return (
<div className="modal-container" onClick={this.onOverlayClick}>
<div className="modal">
<button onClick={this.hideModal}>close modal</button>
</div>
</div>
);
}
}
And now, when menu and modal is open, on close modal click or modal overlay click I want to close only modal, menu should be still open. Only on second click (while modal is closed). At first glance it look pretty clear and easy, this condition should be responsible for that:
if (displayModal || this.node.contains(target)) {
return;
}
If displayModal is true
, nothing should happen. I'ts do not work, cause in my case, when you click at the close modal button or overlay, hideModal
will be done faster than toggleMenu
, and when we call handleClickOutside
displayModal will already have false
.
Full test case with open menu and modal at the start: