모달은 기본적으로 페이지 위에 표시되는 오버레이로, 전체 페이지에 대한 오버레이이기 때문에 다른 모든 요소들 위에 있어야 한다.
react-dom 라이브러리에 있는 portal을 사용해 보자!
모달을 root 요소 위로, 즉 body 바로 아래 요소로 렌더되게 해보자.
backdrop-root
, overlay-root
루트를 만들어서 여러 다른 종류의 컴포넌트를 해당 루트로 포털되도록 한다.<body>
<div id="backdrop-root"></div>
<div id="overlay-root"></div>
<div id="root"></div>
</body>
backdrop-root
에는 오버레이될 때 배경 짙어지는 효과나는 컴포넌트 포털되게overlay-root
에는 모든 오버레이 컴포넌트(모달, 사이드 드로어 등)가 포털되게import ReactDOM from "react-dom";
먼저 react-dom 라이브러리에 있는 portals을 사용하기 위해 react-dom을 임포트 한다.
JSX를 반환하는 컴포넌트 각각 만들기
{ReactDOM.createPortal(children, containder)}
createPortal()은 2가지 인자를 가진다.
<컴포넌트 props />
)document.getElementById("")
)즉, {ReactDOM.createPortal(보낼 리액트돔-JSX, 보내질 장소인 리얼돔 위치-DOM API)}
이라고 생각하면 된다.
import React from "react";
// 1. react-dom 라이브러리에 있는 portals을 사용하기 위해 react-dom을 임포트 한다.
import ReactDOM from "react-dom";
import Card from "./Card";
import Button from "./Button";
import classes from "./ErrorModal.module.css";
//2-1. backdrop 클래스 가진 JSX 반환하는 컴포넌트
// -> backdrop-root로 포털되게하기
const Backdrop = (props) => {
return <div className={classes.backdrop} onClick={props.onConfirm} />;
};
//2-2. modal 클래스 가진 JSX 반환하는 컴포넌트
// -> overlay-root로 포털되게하기
const ModalOverlay = (props) => {
return (
<Card className={classes.modal}>
<header className={classes.header}>
<h2>{props.title}</h2>
</header>
<div className={classes.content}>
<p>{props.message}</p>
</div>
<footer className={classes.actions}>
<Button onClick={props.onConfirm}>Okay</Button>
</footer>
</Card>
);
};
// 3. Portal사용하여 Real DOM의 다른 위치로 ReactDOM JSX를 보내기
//{ReactDOM.createPortal(리액트돔-JSX, 리얼돔 위치-DOM API)}
const ErrorModal = (props) => {
return (
<>
{ReactDOM.createPortal(
<Backdrop onConfirm={props.onConfirm} />,
document.getElementById("backdrop-root")
)}
{ReactDOM.createPortal(
<ModalOverlay
title={props.title}
message={props.message}
onConfirm={props.onConfirm}
/>,
document.getElementById("overlay-root")
)}
</>
);
};
export default ErrorModal;
포털의 핵심은 Real DOM에 렌더링될 위치를 설정하고, JSX 코드 안에서 렌더링된 HTML 내용을 그 위치로 옮기는 것이다. 즉 이동시키는 것이 핵심이다.
📍 /src/index.js
에서도 DOM API인 getElementById를 사용하여 선택한 root 요소로 App 컴포넌트를 render()메소드로 렌더링했다.<Backdrop />
, <ModalOverlay />
)를 다른 장소("backdrop-root"와 "overlay-root")
로 이동시킨다.참고
모달과 팝업