# 리액트 - 모달창 초간단 구현 방법
HTML 에서 기본 제공하는 dialog 엘리먼트를 이용하면, 아래의 2가지를 아주 쉽게 구현할 수 있다.
1. 모달창
2. 다이얼로그
모달창과 다이얼로그의 차이는
- 모달창: dialog 엘리먼트 외부 영역이 불투명하게 dim 처리되고, 스크롤을 제외한 인터랙션(클릭 등)이 허용되지 않는다.
- 다이얼로그: 툴팁처럼 노출되며 인터랙션에 영향을 미치지 않는다.
dialog 엘리먼트를 이용하면,
React에서 useState 나 외부 상태 관리 라이브러리 등을 사용하지 않아도 아주 쉽게 모달창을 구현할 수 있다.
당연히 Next.js 13 환경에서도 동일하게 모달창을 구현할 수 있다.
1. 모달창
dialog 엘리먼트는 비노출 상태가 디폴트이며,
(open 속성을 true로 주면 노출 상태가 디폴트가 되긴하지만, 아래의 방법을 추천.)
모달창을 노출/비노출시키는 방법은 다음과 같다.
- showModal() 메서드를 호출하면 모달창이 노출된다. (cf. 다이얼로그는 show() 메서드를 호출하면 노출된다)
- close() 메서드를 호출하면 모달창이 사라진다.
React에서는 아래와 같이 간단하게 모달창을 구현할 수 있다.
"use client"; // Next.js 13 환경인 경우, 필요에 따라 클라이언트 컴포넌트 사용
import React, { useEffect, useRef } from "react";
export default function Modal() {
// dialog 참조 ref
const dialogRef = useRef<HTMLDialogElement>(null);
// modal 오픈 함수
const showModal = () => {
dialogRef.current?.showModal(); // 모달창 노출. show() 호출하면 다이얼로그 노출
};
// Modal 닫기 함수
const closeModal = () => {
dialogRef.current?.close(); // 모달창 닫기
};
return (
<div>
{/* 모달 노출 버튼 */}
<button onClick={showModal}>Open Modal</button>
{/* dialog 엘리먼트 - 모달창 영역 */}
<dialog ref={dialogRef}>
<div>
{/* 제목 + X버튼 영역 */}
<span>기본 타이틀</span>
<button onClick={closeModal}>X버튼</button>
</div>
<div>
{/* 컨텐츠 영역 */}
<p>기본 컨텐츠가 표시됩니다</p>
</div>
<div>
{/* 확인 버튼 영역 */}
<button onClick={closeModal}>확인</button>
</div>
</dialog>
</div>
);
}
위의 Modal 컴포넌트를 아래와 같이 사용해주면 된다.
import Modal from "./Modal";
export default function ModalPage() {
return (
<div>
<h1>ModalPage</h1>
<Modal />
</div>
);
}
[결과 화면: Open Modal 버튼을 누르면 모달창이 노출된다.]
2. 다이얼로그
show() 메서드를 호출하면, (모달창이 아니라) 다이얼로그가 노출된다.
모달창과 달리 dialog 외부 영역 클릭 등이 가능하다.
이 외에는 작동방식과 구현방법 등이 모두 모달창과 동일하다.
끝!
아주 기본적인 모달창을 구현만 필요하다면, 정말 이걸로 끝이다.
하지만 아래의 3가지 내용이 추가 된다면 훨씬 더 훌륭한 모달창이 될 것이다.
1. 배경 dim 처리 영역 스타일링
2. Props로 title, content 등 전달 받기
3. 모달창 외부의 불투명 dim영역 클릭시, 모달창 닫기 구현
1. 모달창 배경 dim 처리 영역 스타일링
::backdrop 선택자를 사용하면 dim처리영역을 스타일링 할 수 있다.
.dialog::backdrop {
background-color: rgba(0, 255, 0, 0.4);
}
.dialog {
width: 50vw;
background-color: green;
border: 3px solid blue;
}
- 외부 dim 처리 영역을 불투명한 초록색으로,
- 모달창은 노란색, 테두리를 파란색으로 설정해보았다.
2. Props로 모달창 title, content 등 전달 받기
기본적인 React의 Prop 사용 방식을 사용하면 된다.
"use client";
import React, { useEffect, useRef } from "react";
import styles from "./Modal.module.css";
type Props = {
title?: string; // 모달창 제목을 Prop으로 받을 수 있다.
content?: string; // 모달창 컨텐츠를 Prop으로 받을 수 있다.
onConfirm?: () => void; // 모달창의 확인 버튼 클릭시, 실행할 함수를 Prop으로 받을 수 있다.
};
export default function Modal({ title, content, onConfirm }: Props) {
// dialog 참조 ref
const dialogRef = useRef<HTMLDialogElement | null>(null);
// modal 오픈 함수
const showModal = () => {
dialogRef.current?.showModal(); // 모달창 노출. show() 호출하면 다이얼로그 노출
};
// Modal 닫기 함수
const closeModal = () => {
dialogRef.current?.close(); // 모달창 닫기
};
return (
<div>
{/* 모달 노출 버튼 */}
<button onClick={showModal}>Open Modal</button>
{/* dialog 엘리먼트 - 모달창 영역 */}
<dialog ref={dialogRef} className={styles.dialog}>
<div>
{/* 제목 + X버튼 영역 */}
<span>{title || "기본 타이틀"}</span>
<button onClick={closeModal}>X버튼</button>
</div>
<div>
{/* 컨텐츠 영역 */}
<p>{content || "기본 컨텐츠가 표시됩니다."}</p>
</div>
<div>
{/* 확인 버튼 영역 */}
<button onClick={onConfirm || closeModal}>확인</button>
</div>
</dialog>
</div>
);
}
Modal 컴포넌트를 부르는 부모 컴포넌트에서는 아래와 같이 사용해주면 된다.
"use client";
import Modal from "./Modal";
export default function ModalPage() {
return (
<div>
<h1>ModalPage</h1>
<Modal
title="부모의 명령"
content="내가 내려주는 컨텐츠를 노출하도록 하라"
onConfirm={() => {
alert("onConfirm이 호출되었어요~");
}}
/>
</div>
);
}
[결과 화면: 모달창의 "확인" 버튼을 누르면 팝업이 노출된다.]
3. 모달창 외부의 불투명 dim영역 클릭시, 모달창 닫기 구현
모달창 외부의 영역이 클릭되면, 모달창을 닫도록 이벤트 리스너를 장착해주면 된다.
React 환경이므로, useEffect에서 정의 해주었다.
"use client";
import React, { useEffect, useRef } from "react";
import styles from "./Modal.module.css";
type Props = {
title?: string; // 모달창 제목을 Prop으로 받을 수 있다.
content?: string; // 모달창 컨텐츠를 Prop으로 받을 수 있다.
onConfirm?: () => void; // 모달창의 확인 버튼 클릭시, 실행할 함수를 Prop으로 받을 수 있다.
};
export default function Modal({ title, content, onConfirm }: Props) {
// dialog 참조 ref
const dialogRef = useRef<HTMLDialogElement | null>(null);
// modal 오픈 함수
const showModal = () => {
dialogRef.current?.showModal(); // 모달창 노출. show() 호출하면 다이얼로그 노출
};
// Modal 닫기 함수
const closeModal = () => {
dialogRef.current?.close(); // 모달창 닫기
};
useEffect(() => {
// 모달창 외부영역 클릭시, 모달창 닫기 구현
if (dialogRef.current) {
const dialogElement = dialogRef.current as HTMLDialogElement;
dialogElement.addEventListener("click", (event) => {
const dialogArea = dialogElement.getBoundingClientRect();
if (
event.clientX < dialogArea.left ||
event.clientX > dialogArea.right ||
event.clientY < dialogArea.top ||
event.clientY > dialogArea.bottom
) {
dialogElement.close();
}
});
}
}, []);
return (
<div>
{/* 모달 노출 버튼 */}
<button onClick={showModal}>Open Modal</button>
{/* dialog 엘리먼트 - 모달창 영역 */}
<dialog ref={dialogRef} className={styles.dialog}>
<div>
{/* 제목 + X버튼 영역 */}
<span>{title || "기본 타이틀"}</span>
<button onClick={closeModal}>X버튼</button>
</div>
<div>
{/* 컨텐츠 영역 */}
<p>{content || "기본 컨텐츠가 표시됩니다."}</p>
</div>
<div>
{/* 확인 버튼 영역 */}
<button onClick={onConfirm || closeModal}>확인</button>
</div>
</dialog>
</div>
);
}
각자의 개발 구조에 따라, 이벤트 리스너 해제 등의 세부 구현은 상황에 맞게 진행 하시면 좋을듯 합니다.
HTML dialog 엘리먼트를 사용하지 않고,
수동으로 모달창을 구현하려면, 아래 글을 참고하시기 바랍니다.
[React] 모달창(Modal) 초간단 구현 방법(리덕스, 라이브러리 X)
'개발(Development) > React(리액트)' 카테고리의 다른 글
[Next.js 13] async 서버 컴포넌트 JSX/Promise 반환 에러 해결 방법 (0) | 2023.05.12 |
---|---|
[React] 리액트 사이드 이펙트(Side-effect) 의미, 종류(feat. 순수함수) (0) | 2023.05.06 |
[React] Next.js 환경 구글 애널리틱스(GA) 적용 방법 (0) | 2022.09.22 |
[React] 카카오 애드핏 적용 방법(Next.js 환경) (0) | 2022.09.22 |
[Next.js] 환경변수 사용 방법: .env파일 (development, production, local) (0) | 2022.08.25 |
댓글