createPortal
모달은 사용자에게 항상 최우선으로 출력되어야 하는 경우가 많습니다. react의 DOM tree를 보면, 모든 컴포넌트가 최상위 컨테이너인 root(<div id="root">)에 종속되는데, 모달의 경우에는 어느 컴포넌트에서 호출이 되어도 모든 컴포넌트 위에 존재합니다. 따라서 물리적인 구조상 root를 벗어나는 것이 더 깔끔할 수 있습니다.
모달 뿐만이 아니라 애플리케이션 내에서 리액트 코드를 부분적으로만 사용하는 경우에도 root 이외의 DOM tree를 구성해야 하는 경우가 있습니다. 이럴 때 createPortal을 사용하면 컴포넌트를 기존의 DOM tree에서 물리적으로 분리할 수 있습니다.
구문
react-dom 패키지의 createPortal을 사용해 줍니다.
createPortal(children, domNode, key?);
children | 모달 컴포넌트 |
domNode | 모달 컴포넌트를 종속시킬 루트 레벨의 요소 |
예시
1. root div와 같은 레벨에 <div id="modal"> 컨테이너를 추가해 줍니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="modal"></div> <!-- 추가 -->
</body>
</html>
2. 모달 컴포넌트에서 JSX를 반환할 때 createPortal을 사용합니다.
import { createPortal } from "react-dom";
function Modal(props) {
const { message } = props;
return createPortal(
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
position: "fixed",
bottom: 30,
left: 0,
width: "100%",
height: 50,
}}
>
<div
style={{
width: "30%",
textAlign: "center",
borderRadius: 30,
background: "grey",
fontSize: 20,
color: "white",
}}
>
<p>{message}</p>
</div>
</div>,
document.getElementById("modal")
);
}
export default Modal;
이제 Modal 컴포넌트는 기존의 root 계층에서 분리되어 modal 컨테이너에 렌더링 됩니다. 단, 물리적인 위치만 분리되어 있을 뿐, 데이터나 이벤트 버블링 등의 논리적인 흐름은 root 내부에 있는 것과 동일합니다. 예를 들어 위 코드에서 Modal 컴포넌트가 받는 props는 여전히 해당 컴포넌트의 부모 컴포넌트에 의해서 전달됩니다.
'리액트' 카테고리의 다른 글
[react] JSX 배열 반복문 렌더링 - for, map, forEach (1) | 2024.01.04 |
---|---|
[react] 리액트 전체화면 넘기기 스크롤링(full page scroll) (11) | 2021.06.18 |
[react] 불필요한 리렌더링 방지하기 - React.memo 성능 최적화 (1) | 2019.12.23 |
[react] 올바른 리액트 조건부 렌더링 (if else 구문과 ternary operator, && 차이) (1) | 2019.09.09 |
[react] 리액트 react-router-dom 사용법 - BrowserRouter, Route, Switch, Link (4) | 2019.08.27 |