'My custom modal doesn't close because of react's useState hook
My custom modal window opens up but doesn't close when I click on the darkened area. I investigated a bit and found out that the setActive function in the modal component doesn't set the active to false for some reason. How can I fix this?
The modal file
import React from 'react'
import './style.css'
const Modal = ({active, setActive, children}) => {
return (
<div className={active?'modal_main active':'modal_main'} onClick={()=>{setActive(false)}}>
<div className={active?'modal_content active':'modal_content'} onClick={e=>e.stopPropagation()}>
{children}
</div>
</div>
)
}
export default Modal
Where I use the modal window
import React, { useState } from 'react'
import Modal from '../../modal'
import './style.css'
function TagItem(props) {
const [tagActive, setTagActive] = useState(false);
return (
<div className='tag-item' onClick={()=>setTagActive(true)}>
{props.tag}
<Modal active = {tagActive} setActive = {setTagActive}>
<div >{props.tag}</div>
</Modal>
</div>
)
}
export default TagItem
modal's css
.modal_main{
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.4);
position: fixed;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
pointer-events: none;
transition: 0.5s;
z-index:1;
}
.modal_main.active{
opacity: 1;
pointer-events: all;
}
.modal_content{
padding: 20px;
border-radius: 12px;
background-color: white;
height: fit-content;
width: fit-content;
transform: scale(0.5);
transition: 0.4s all;
}
.modal_content.active{
transform: scale(1);
}
tag-item's css
.tag-item{
border: 1px limegreen solid;
border-radius: 8px;
background-color: rgb(178, 246, 119);
width: fit-content;
padding: 2px;
margin: 2px;
cursor: default;
}
.tag-item:hover{
cursor: default;
background-color: rgb(1, 152, 1) ;
}
Solution 1:[1]
Issue
The click event from the modals's outer div elementis triggering the state update, but it's also propagated out of theModalcomponent to theTagItemcomponent'sdivelement and this enqueues atagActivestate update totrue`. The state update to close the modal is overwritten.
Solution
Stop the propagation of the outer div element's click event.
const Modal = ({ active, setActive, children }) => {
return (
<div
className={active ? "modal_main active" : "modal_main"}
onClick={(e) => {
e.stopPropagation(); // <-- stop propagation to parent component
setActive(false);
}}
>
<div
className={active ? "modal_content active" : "modal_content"}
onClick={(e) => {
e.stopPropagation();
}}
>
{children}
</div>
</div>
);
};
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Drew Reese |
