1. Portals?
DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링 하는 최고의 방법이다.
일반적으로 컴포넌트를 렌더링 메서드에서 엘리먼트를 반환할 때 부모 노드에서 가장 가까운 자식으로 DOM이
마운트 된다.
그런데 가끔 DOM의 다른 위치에서 자식을 삽입하는 것이 유용할 수 있다.
예를 들어, overflow: hidden이나 z-index가 있는 경우 시각적으로 자식을 "튀어나오도록" 보여야 하는 경우가 있다.
다이얼로그, 툴팁 같은 것 말이다.
2. 필요성
import React, { useState } from "react";
export default function Portals(props) {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button
style={{
position: "absolute",
left: 100,
}}
onClick={() => setIsOpen(true)}
>
open
</button>
{isOpen && (
<div
style={{
position: "absolute",
zIndex: 99,
top: `50%`,
left: `50%`,
transform: "translate(-50%,-50%)",
border: "1px solid black",
padding: 24,
backgroundColor: "white",
}}
>
<p>{props.title}</p>
<p>{props.description}</p>
<button onClick={() => setIsOpen(false)}>OK</button>
</div>
)}
{isOpen && (
<div
style={{
position: `fixed`,
backgroundColor: "grey",
top: 0,
left: 0,
bottom: 0,
right: 0,
}}
/>
)}
</>
);
}
간단하게 버튼을 누르면 화면이 모두 가려지고 다이얼로그가 나오는 컴포넌트를 만들었다.
import React from "react";
import Portals from "./PortalDialog";
export default function Example() {
return (
<div>
<Portals title={"Hello!"} description={"Portal Example"} />
<div style={{ position: "absolute" }}>
<button>하하하</button>
</div>
</div>
);
}
부모 컴포넌트에서 다이알로그를 호출하고, 바로 아래에 " 하하하 " 버튼이 출력되게 작성하였다.
이때, 다이알로그에서는 position: "absolute" 그리고 배경을 postion: "fixed"를 주어서 모두 가리는 작업을 했는데,
부모 컴포넌트의 또다른 자식 컴포넌트인 " 하하하 " 버튼은 사라지지 않았다.
<div>
<div style={{ position: "absolute" }}>
<button>하하하</button>
</div>
<Portals title={"Hello!"} description={"Portal Example"} />
</div>
물론 Portals 태그와 button이 있는 div의 순서를 바꾼다면 " 하하하 " 버튼은 사라질 것이다.
그렇지만, 작은 프로젝트에서는 가능할지라도 여러 가지 컴포넌트를 사용하는 경우 순서를 바꾸는 게 쉬운 일은 아니다.
정리하면, 모든 레이어가 순차적으로 가지고 있는 Stack을 벗어나는 일을 해야 할 경우에 Portal이 필요하다.
3. 사용하기
사용방법은 생각보다 간단하다.
pubilc 폴더에 있는 index.html 파일의 root div 아래에 portal div를 한 개 추가해준다.
import React from "react";
import { createPortal } from "react-dom";
import Portals from "./PortalDialog";
const Portal = (props) => {
return createPortal(props.childre, document.getElementById("portal"));
};
export default function Example() {
return (
<div>
<Portal>
<Portals title={"Hello!"} description={"Portal Example"} />
</Portal>
<div style={{ position: "absolute" }}>
<button>하하하</button>
</div>
</div>
);
}
그리고 createPortal()을 사용해서 Portal 컴포넌트를 만들고 다이얼로그를 감싸주면 된다.
이렇게 작업을 한다면 Portals 다이얼로그가 root div에 만들어지는 것이 아닌 portal div에 만들어지게 된다.
'React > 패스트캠퍼스' 카테고리의 다른 글
[React - 기초] PropTypes (2) | 2022.03.19 |
---|---|
[React - 기초] Render Props (1) | 2022.03.18 |
[React - 기초] Memoization (2) | 2022.03.15 |
[React - 기초] Hooks (0) | 2022.03.10 |
[React - 기초] React와 리랜더링 (0) | 2022.03.09 |