예전에 CSS와 자바스크립트를 이용해서 모달창을 구현했습니다. 마찬가지로 리액트로도 모달창을 구현할 수 있는데요. 바닐라 자바스크립트와는 조금 다르기에 방법을 소개해보려고 합니다.
제가 소개드린 방식으로도 리액트 환경에서 모달을 구현할 수 있습니다.
classList
속성을 통해서 DOM요소에 직접 접근하여 class를 수정함으로써 모달창을 구현했었는데요. 리액트에서는 직접적으로 DOM요소를 조작하는 것을 지양하고 있습니다.
리액트는 Virtual DOM을 통해, 미리 렌더링을 하게 됩니다. 이 과정에서 필요한 부분만 리렌더링해서 효율성을 챙겼는데요. 우리가 리액트에서 DOM 요소를 직접 조작한다는 것은 리액트의 효율성을 해치는 일을 한다는 것 입니다.
따라서 우리는 리액트에서 직접 DOM 조작을 피하기 위해 모달창을 조금 다른 방식으로 구현해보려고 합니다.
이번 모달은 버튼을 누르면 닫히는 기능과 모달 영역 외부를 클릭하면 닫히는 기능 두 가지를 모두 구현했습니다.
const App = () => {
const [modalOpen, setModalOpen] = useState(false);
const modalBackground = useRef();
return (
<>
<div className={'btn-wrapper'}>
<button className={'modal-open-btn'} onClick={() => setModalOpen(true)}>
모달 열기
</button>
</div>
{
modalOpen &&
<div className={'modal-container'} ref={modalBackground} onClick={e => {
if (e.target === modalBackground.current) {
setModalOpen(false);
}
}}>
<div className={'modal-content'}>
<p>리액트로 모달 구현하기</p>
<button className={'modal-close-btn'} onClick={() => setModalOpen(false)}>
모달 닫기
</button>
</div>
</div>
}
</>
);
};
export default App;
const [modalOpen, setModalOpen] = useState(false); const modalBackground = useRef();
modalOpen
은 모달창을 표지할지에 대한 true/false값을 담은 state입니다.modalBackground
는 모달의 바깥(여기서는 콘텐츠 바깥의<div>
)을 클릭했을 때 닫힐 수 있도록 하기 위해 선언한ref
입니다. 이 ref를 바깥이 되는 영역에 전달하면 DOM을 조작할 수 있게 됩니다.
return (
<>
<div className={'btn-wrapper'}>
<button className={'modal-open-btn'} onClick={() => setModalOpen(true)}>
모달 열기
</button>
</div>
{
modalOpen &&
<div className={'modal-container'} ref={modalBackground} onClick={e => {
if (e.target === modalBackground.current) {
setModalOpen(false);
}
}}>
<div className={'modal-content'}>
<p>리액트로 모달 구현하기</p>
<button className={'modal-close-btn'} onClick={() => setModalOpen(false)}>
모달 닫기
</button>
</div>
</div>
}
</>
);
<button className={'modal-open-btn'} onClick={() => setModalOpen(true)}> 모달 열기 </button>
- 버튼을 누르면 모달창이 열립니다. 이때
onClick
이벤트로 state를 조작해 모달이 열리도록 합니다.
{ modalOpen && <div className={'modal-container'} ref={modalBackground} onClick={e => { if (e.target === modalBackground![](https://velog.velcdn.com/images/bami/post/c49c2a78-1889-4079-b005-b8246129294e/image.gif) .current) { setModalOpen(false); } }}> <div className={'modal-content'}> <p>리액트로 모달 구현하기</p> <button className={'modal-close-btn'} onClick={() => setModalOpen(false)}> 모달 닫기 </button> </div> </div> }
- 모달 구현에는 조건부 렌더링을 이용합니다.
modalOpen
state가 true이면 모달창이 보여지게 됩니다.- 콘텐츠 외부를 클릭하면 닫히도록
<div className={'modal-container}>
에 ref를 전달했습니다. 이때onClick
이벤트를 통해 이벤트가 ref로 지정된 영역에서 발생하면modalOpen
state를 false로 만들어서 모달이 안보이도록 만들어줍니다.- 콘텐츠에도 버튼을 삽입해서
onClick
이벤트를 통해 버튼을 누르면modalOpen
을 false로 만들어 모달이 안보이도록 만들었습니다.
이번에는 리액트로 구현하는 게 목적이므로, css에 대한 설명은 이전 포스트를 참조해주시기 바랍니다.
.btn-wrapper {
display: flex;
justify-content: center;
margin-top: 5rem;
}
.modal-open-button, .modal-close-btn {
cursor: pointer;
margin-left: auto;
}
.modal-container {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.5);
}
.modal-content {
background-color: #ffffff;
width: 250px;
height: 150px;
padding: 15px;
}
도움받았습니다! 감사합니다.