createPortal
createPortal
은 일부 자식(children)을 DOM의 다른 위치에 렌더링할 수 있게 해줍니다.
<div>
<SomeComponent />
{createPortal(children, domNode, key?)}
</div>
- 레퍼런스
- createPortal(children, domNode, key?)
- 사용법
- DOM의 다른 위치에 렌더링하기
- 포털로 모달 다이얼로그 렌더링하기
- React 컴포넌트를 비-React 서버 마크업에 렌더링하기
- React 컴포넌트를 비-React DOM 노드에 렌더링하기
레퍼런스
createPortal(children, domNode, key?)
포털을 만들려면 createPortal
을 호출하고, 렌더링할 JSX와 렌더링할 DOM 노드를 전달하세요:
import { createPortal } from 'react-dom';
// ...
<div>
<p>This child is placed in the parent div.</p>
{createPortal(
<p>This child is placed in the document body.</p>,
document.body
)}
</div>
아래 예시를 참고하세요.
포털은 DOM 노드의 물리적 위치만 변경합니다. 그 외의 모든 면에서, 포털로 렌더링된 JSX는 포털을 렌더링한 React 컴포넌트의 자식 노드로 동작합니다. 예를 들어, 자식은 부모 트리에서 제공된 context에 접근할 수 있고, 이벤트도 React 트리 기준으로 버블링됩니다.
파라미터
children
: React로 렌더링할 수 있는 모든 것(JSX,<div />
,<SomeComponent />
, Fragment, 문자열, 숫자, 배열 등)domNode
:document.getElementById()
등으로 얻은 DOM 노드. 반드시 이미 존재하는 노드여야 합니다. 업데이트 시 다른 DOM 노드를 전달하면 포털 내용이 재생성됩니다.- optional
key
: 포털의 key로 사용할 고유 문자열 또는 숫자(선택).
반환값
createPortal
은 JSX에 포함하거나 컴포넌트에서 반환할 수 있는 React 노드를 반환합니다. React가 이를 렌더링하면, 전달한 children
을 지정한 domNode
에 배치합니다.
주의사항
- 포털에서 발생한 이벤트는 DOM 트리가 아니라 React 트리 기준으로 버블링됩니다. 예를 들어, 포털 내부에서 클릭하면, 포털을 감싸는
<div onClick>
의 핸들러가 실행됩니다. 이로 인해 문제가 발생한다면, 포털 내부에서 이벤트 전파를 중단하거나, 포털 자체를 React 트리 상위로 옮기세요.
사용법
DOM의 다른 위치에 렌더링하기
포털(portal)은 컴포넌트의 일부 자식을 DOM의 다른 위치에 렌더링할 수 있게 해줍니다. 이를 통해 컴포넌트의 일부가 컨테이너를 "탈출"하여 페이지의 다른 곳에 표시될 수 있습니다. 예를 들어, 모달 다이얼로그나 툴팁을 페이지의 나머지 위에 띄울 때 유용합니다.
import { createPortal } from 'react-dom';
function MyComponent() {
return (
<div style={{ border: '2px solid black' }}>
<p>This child is placed in the parent div.</p>
{createPortal(
<p>This child is placed in the document body.</p>,
document.body
)}
</div>
);
}
React는 전달한 JSX의 DOM 노드를 지정한 DOM 노드에 배치합니다.
포털이 없으면 두 번째 <p>
는 부모 <div>
내부에 위치하지만, 포털을 사용하면 해당 요소가 document.body로 "텔레포트"됩니다.
<body>
<div id="root">
...
<div style="border: 2px solid black">
<p>This child is placed inside the parent div.</p>
</div>
...
</div>
<p>This child is placed in the document body.</p>
</body>
포털은 DOM 노드의 위치만 바꿀 뿐, context나 이벤트 버블링 등은 여전히 React 트리 기준으로 동작합니다.
포털로 모달 다이얼로그 렌더링하기
포털을 사용하면, 페이지의 나머지 위에 떠 있는 모달 다이얼로그를 만들 수 있습니다. 예를 들어, 부모 컨테이너에 overflow: hidden
등 스타일이 적용되어 있어도, 포털로 렌더링된 모달은 영향을 받지 않습니다.
접근성을 위해 포털을 사용할 때는 키보드 포커스 관리 등도 신경써야 합니다. WAI-ARIA Modal Authoring Practices를 참고하세요. 커뮤니티 패키지를 사용할 경우에도 접근성 가이드라인을 준수하는지 확인하세요.
React 컴포넌트를 비-React 서버 마크업에 렌더링하기
포털은 React 루트가 정적/서버 렌더링된 페이지의 일부일 때도 유용합니다. 예를 들어, Rails 등 서버 프레임워크로 빌드된 페이지에서, React로 만든 인터랙티브 영역을 사이드바 등 정적 영역에 삽입할 수 있습니다. 여러 개의 React 루트를 사용하는 것보다, 포털을 사용하면 하나의 React 트리로 상태를 공유할 수 있습니다.
import { createPortal } from 'react-dom';
const sidebarContentEl = document.getElementById('sidebar-content');
export default function App() {
return (
<>
<MainContent />
{createPortal(
<SidebarContent />,
sidebarContentEl
)}
</>
);
}
function MainContent() {
return <p>This part is rendered by React</p>;
}
function SidebarContent() {
return <p>This part is also rendered by React!</p>;
}
React 컴포넌트를 비-React DOM 노드에 렌더링하기
포털을 사용하면 React 외부에서 관리되는 DOM 노드의 내용을 제어할 수도 있습니다. 예를 들어, 비-React 지도 위젯의 팝업에 React 콘텐츠를 렌더링하려면 다음과 같이 할 수 있습니다.
const [popupContainer, setPopupContainer] = useState(null);
useEffect(() => {
if (mapRef.current === null) {
const map = createMapWidget(containerRef.current);
mapRef.current = map;
const popupDiv = addPopupToMapWidget(map);
setPopupContainer(popupDiv);
}
}, []);
return (
<div style={{ width: 250, height: 250 }} ref={containerRef}>
{popupContainer !== null && createPortal(
<p>Hello from React!</p>,
popupContainer
)}
</div>
);