1. 알아야 할 내용
- 아래 코드는 모달 창의 'X' 버튼이 아닌 여백 아무 곳이나 클릭해도 창이 사라지는 것(이벤트 버블링)을 막기 위해 필요하다.
const stopEvent = (event) => { event.stopPropagation() };
- 모달이 띄워졌을 때 뒷 배경의 스크롤을 막기 위해 기존 이벤트 핸들러 1개로 동작하는 구조에서 모달을 띄우는 이벤트 핸들러, 닫는 이벤트 핸들러 2개로 나눈 후 띄우는 이벤트 핸들러에는 body의 스크롤을 막고, 닫는 이벤트 핸들러에는 body의 스크롤을 다시 동작하는 코드를 추가한다.
- 기존 모달 on/off 이벤트 핸들러 상태에서는 모달이 열려도 뒷 배경에 스크롤이 동작하는 것을 볼 수 있다.
const openModalHandler = () => {
setIsOpen(!isOpen)
};
<button onClick={openModalHandler}>Open</button>
<div className='closebtn' onClick={openModalHandler}>X</div>
- 뒷 배경의 스크롤을 막기 위해 2개로 나눈 모달 on/off 이벤트 핸들러 상태에서는 뒷 배경 스크롤이 동작하지 않는 것을 볼 수 있다.
const openModalHandler = () => {
setIsOpen(!isOpen);
document.body.style.cssText = `
position: fixed;
top: -${window.scrollY}px;
overflow-y: scroll;
width: 100%;`;
};
const closeModalHandler = () => {
setIsOpen(!isOpen);
const scrollY = document.body.style.top;
document.body.style.cssText = '';
window.scrollTo(0, parseInt(scrollY || '0', 10) * -1);
};
<button onClick={openModalHandler}>Open</button>
<div className='closebtn' onClick={closeModalHandler}>X</div>
2. 전체 코드
import { useState } from 'react';
import styled from 'styled-components';
const ModalBackdrop = styled.div`
position: fixed;
z-index: 999;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(0,0,0,0.4);
display: grid;
place-items: center;
`;
const ModalView = styled.div`
border-radius: 5px;
background-color: white;
width: 700px;
height: 430px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.19), 0 10px 10px rgba(0, 0, 0, 0.1);
> .closebtn {
text-align: center;
margin-bottom: 50px;
font-size: 30px;
&:hover {
color: gray;
}
}
> .content {
text-align: center;
font-size: 50px;
}
`;
export const Modal = () => {
const [isOpen, setIsOpen] = useState(false);
const openModalHandler = () => {
setIsOpen(!isOpen);
document.body.style.cssText = `
position: fixed;
top: -${window.scrollY}px;
overflow-y: scroll;
width: 100%;`;
};
const closeModalHandler = () => {
setIsOpen(!isOpen);
const scrollY = document.body.style.top;
document.body.style.cssText = '';
window.scrollTo(0, parseInt(scrollY || '0', 10) * -1);
};
const stopEvent = (event) => { event.stopPropagation() };
return (
<>
<button onClick={openModalHandler}>Open</button>
{isOpen ?
<ModalBackdrop onClick={openModalHandler}>
<ModalView onClick={stopEvent}>
<div className='closebtn' onClick={closeModalHandler}>X</div>
<div className='content'>Modal content</div>
</ModalView>
</ModalBackdrop> : null}
</>
);
};