이 글은 useState, useRef 등만을 활용하여 수동으로 모달창을 구현하는 방법입니다.
이 것만으로도 이미 충분히 간단하지만,
만약 HTML의 dialog 엘리먼트로 훨씬 더 쉽게 구현하는 방법이 필요하시다면, 아래 글을 참고해주세요.
[React] 모달창(Modal) 쉽고 간단한 구현 방법 (HTML dialog 엘리먼트 사용)
# 리액트 모달창 구현 방법
- redux나 별도 라이브러리 없이 아주 쉽게 모달창을 구현하는 방법
1. state 로 Modal 노출 여부를 관리한다.
- useState 훅으로 모달창 노출 여부를 관리해준다.
2. Modal 창이 최상위에 노출되도록 CSS를 조정한다.
- position: absolute로 위치를 조정한다.
- z-index를 높게 줘서 최상위에 노출 시킨다.
3. (옵션) 모달창 외부 클릭시, 모달창 제거 처리해준다.
- 모달창 외부 document 클릭 이벤트를 달아준다.
1. state 로 Modal 노출 여부를 관리한다.
- button을 클릭하면, setModalOpen(true)를 호출한다.
- modalOpen이 true가 되면, <ModalBasic /> 컴포넌트가 노출된다.
- <ModalBasic /> 컴포넌트 내부에 X버튼 클릭시, 모달 제거를 위해 setModalOpen을 props 로 전달한다.
< 모달을 노출시키는 페이지 컴포넌트 >
import { useState } from 'react';
import ModalBasic from '../src/common/ModalBasic';
// 모달을 노출하는 페이지
function Modal() {
// 모달창 노출 여부 state
const [modalOpen, setModalOpen] = useState(false);
// 모달창 노출
const showModal = () => {
setModalOpen(true);
};
return (
<div>
<button onClick={showModal}>모달 띄우기</button>
{modalOpen && <ModalBasic setModalOpen={setModalOpen} />}
</div>
);
}
export default Modal;
< 모달창 컴포넌트 >
import styles from './ModalBasic.module.css';
function ModalBasic({ setModalOpen, id, title, content, writer }: PropsType) {
// 모달 끄기
const closeModal = () => {
setModalOpen(false);
};
return (
<div className={styles.container}>
<button className={styles.close} onClick={closeModal}>
X
</button>
<p>모달창입니다.</p>
</div>
);
}
export default ModalBasic;
(참고) CSS Module 방식을 사용했다.
2. Modal 창이 최상위에 노출되도록 CSS를 조정한다.
- <ModalBasic> 컴포넌트의 CSS를 조정하여, 최상위에 노출되도록 한다.
/* 모달창을 화면 중앙. 최상단에 노출 */
.container {
/* 모달창 크기 */
width: 300px;
height: 200px;
/* 최상단 위치 */
z-index: 999;
/* 중앙 배치 */
/* top, bottom, left, right 는 브라우저 기준으로 작동한다. */
/* translate는 본인의 크기 기준으로 작동한다. */
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* 모달창 디자인 */
background-color: gray;
border: 1px solid black;
border-radius: 8px;
}
/* 모달창 내부 X버튼 */
.close {
position: absolute;
right: 10px;
top: 10px;
}
여기까지만 해도,
버튼을 누르면 모달창을 띄우고, X버튼을 누르면 제거하는 기본 모달 기능은 구현된다.
3. 모달 외부 클릭시, 제거 처리
- document 에 mousedown 이벤트핸들러를 등록하고,
- 모달창 영역이 아닐 경우에만, modalOpen 상태를 false로 전환해준다.
import { useEffect, useRef } from 'react';
import styles from './ModalBasic.module.css';
function ModalBasic({ setModalOpen, id, title, content, writer }: PropsType) {
// 모달 끄기 (X버튼 onClick 이벤트 핸들러)
const closeModal = () => {
setModalOpen(false);
};
// 모달 외부 클릭시 끄기 처리
// Modal 창을 useRef로 취득
const modalRef = useRef<HTMLDivElement>(null);
useEffect(() => {
// 이벤트 핸들러 함수
const handler = () => {
// mousedown 이벤트가 발생한 영역이 모달창이 아닐 때, 모달창 제거 처리
if (modalRef.current && !modalRef.current.contains(event.target)) {
setModalOpen(false);
}
};
// 이벤트 핸들러 등록
document.addEventListener('mousedown', handler);
// document.addEventListener('touchstart', handler); // 모바일 대응
return () => {
// 이벤트 핸들러 해제
document.removeEventListener('mousedown', handler);
// document.removeEventListener('touchstart', handler); // 모바일 대응
};
});
return (
// 모달창을 useRef로 잡아준다.
<div ref={modalRef} className={styles.container}>
<button className={styles.close} onClick={closeModal}>
X
</button>
<p>모달창입니다.</p>
</div>
);
}
export default ModalBasic;
위 3번 코드에서
useEffect 훅을 사용하는 부분은 커스텀훅으로 분리하면,
코드가 더 간결해지고 가독성이 좋아질 것이다.
참고) HTML dailog 엘리먼트를 이용해, 훨씬 쉽게 React에서 모달창을 구현하는 방법은 아래 글을 참고하시기 바랍니다.
[React] 모달창(Modal) 쉽고 간단한 구현 방법 (HTML dialog 엘리먼트 사용)
'개발(Development) > React(리액트)' 카테고리의 다른 글
[Next.js] Link 컴포넌트에 속성 설정 방법(className, target, rel 등) (0) | 2022.08.21 |
---|---|
[Next.js] pages 라우팅 파일명, 컴포넌트 이름 작성 방법 (0) | 2022.08.21 |
[React] useLocation 으로 쿼리 파라미터 취득 방법(URLSearchParams 활용) (0) | 2022.08.16 |
[Next.js] getServerSideProps 에서 undefined 반환 이유 (0) | 2022.08.16 |
[React] JSX 특수 문자/기호 입력 방법(꺽쇠, 괄호, 슬래시 등) (0) | 2022.08.15 |
댓글