This code has worked for me before but i'm not sure what's changed in this other component i'm trying to use it in.
I've tried using hooks to open and close modal and just plain on click event listener but both times it closes on clicking anywhere on the page.
componentDidMount() {
document.addEventListener('click', this.handleOutsideClick);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleOutsideClick);
}
handleOutsideClick = (e) => {
if (this.state.showInfoModal && !this.node.contains(e.target)) this.handleInfoToggle();
console.log(this.state.showInfoModal, e.target, this.node, 'clicked outside');
}
handleInfoToggle = (event) => {
const { showInfoModal } = this.state;
if (event) event.preventDefault();
this.setState({ showInfoModal: !showInfoModal });
};
renderSomething = (args) => {
return(
<span ref={(node) => { this.node = node; }}>
{something === true && <span className={styles.somethingelse}>
<HintIcon onClick={this.handleInfoToggle} /></span>}
<Modal visible={showInfoModal} onCancel={this.handleInfoToggle}>
some information to show
</Modal>
</span>
)
}
render() => {
return (
{this.renderSomething(args)}
)
}
Not sure if this is enough info. but this is driving me nuts.
I also tried adding a dontCloseModal function that someone had suggested:
dontCloseModal = (e) => {
e.stopPropagation();
console.log(e);
this.setState({
showInfoModal: true
});
}
<div onClick={this.dontCloseModal}></div>
(((this would go around the <Modal/>
component )))
const refs = React.createRef(); // Setup to wrap one child
const handleClick = (event) => {
const isOutside = () => {
return !refs.current.contains(event.target);
};
if (isOutside) {
onClick();
}
};
useEffect(() => {
document.addEventListener('click', handleClick);
return function() {
document.removeEventListener('click', handleClick);
};
});
return (element, idx) => React.cloneElement(element, { ref: refs[idx] });
}
export default ClickOutside;
Tried using a component like this ^^ and adding <ClickOutside onClick={this.closeInfoModal()}></ClickOutside>
But same issue with this too- closes on click anywhere including inside modal
After playing with this a little bit, it seems that you should also useRef
here.
This will allow you to control toggling the modal if the user clicks outside and inside the modal's target.
There are a lot of sophisticated ways to achieve this. However, since we are dealing with hooks here, it would be best to use a custom hook.
Introducing useOnClick
💫:
// Custom hook for controling user clicks inside & outside
function useOnClick(ref, handler) {
useEffect(() => {
const listener = event => {
// Inner Click: Do nothing if clicking ref's element or descendent elements, similar to the solution I gave in my comment stackoverflow.com/a/54633645/4490712
if (!ref.current || ref.current.contains(event.target)) {
return;
}
// Outer Click: Do nothing if clicking wrapper ref
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
return;
}
handler(event);
};
// Here we are subscribing our listener to the document
document.addEventListener("mousedown", listener);
return () => {
// And unsubscribing it when we are no longer showing this component
document.removeEventListener("mousedown", listener);
};
}, []); // Empty array ensures that effect is only run on mount and unmount
}
Watch this Demo in CodeSandBox so you can see how this is implemented using hooks.
Welcome to StackOverflow!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With