공식 문서에 따르면 Portal은 부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링하는 최고의 방법을 제공한다고 되어있다.
즉 외부에 존재하는 DOM 노드가 React App DOM 계층 안에 존재하는 것처럼 연결을 해주는 포탈 기능을 제공합니다.
이 말은, 컴포넌트들의 상하 관계, 구조를 가지고 있는 문서인 DOM 상에서, 자식 컴포넌트를 부모 컴포넌트 바깥에 있는 다른 컴포넌트에 전달할 수 있다는 뜻이다.
일반적으로 React 컴포넌트는 document.getElementById('root')
내부에서 렌더링되지만, Portal을 사용하면 루트 외부의 특정 DOM 요소에 렌더링할 수 있다.
import React from "react";
import ReactDOM from "react-dom";
const Modal = ({ children, onClose }) => {
return ReactDOM.createPortal(
<div className="modal-backdrop" onClick={onClose}>
<div className="modal-content">{children}</div>
</div>,
document.getElementById("modal-root") // 여기서 'modal-root'에 렌더링됨
);
};
export default Modal;
Portal을 사용하려면 ReactDOM.createPortal(children, targetElement)
을 사용해야한다.
첫번째 파라미터에는 랜더링할 컴포넌트를 작성하고 두번째 파라미터에는 랜더링할 dom 요소를 지정하면된다.
나의 경우에는 검색창을 클릭하면 검색필터와 키워드를 입력할수가 있다. 하지만 이 검색창을 라우팅하는 별도의 페이지로 만드는것이 아닌 현재페이지에서 modal창으로 띄우는 방법을 생각해보았고 modal 창을 깔끔하게 띄우기위해서는 portal이 적절하다고 생각하였다.
일반적으로 modal은 화면의 최상위에 떠있어야하는데 React의 root 내부에서 모달을 랜더링하면 부모 요소의 overflow: hidden
이나 z-index
속성때문에 가려질수가 있다.
<!-- public/index.html -->
<div id="root"></div>
<div id="modal-root"></div> <!-- 모달이 렌더링될 위치 -->
위와같이 body아래에 root와 함께 modal-root를 둠으로써 부모요소인 root의 영향을 받지않고 modal창을 최상단에 위치할수 있게한다.
Portal은 랜더링위치를 DOM에서 바꾸는것 일뿐, React 트리구조는 변하지 않는다.
부모 컴포넌트의 상태나 props를 여전히 사용할 수 있지만, 실제 DOM 배치는 부모 바깥에 랜더링된다는 사실을 주의하자.