React Portal

eeensu·2023년 8월 4일
0

React 기본

목록 보기
15/22
post-thumbnail

Portal

Portal은 react 애플리케이션에서 모달, 팝업, 툴팁과 같이 현재 컴포넌트 계층 구조의 바깥에 UI를 렌더링하기 위한 기술이다. 이를 통해 DOM 트리의 다른 위치에 컴포넌트를 렌더링할 수 있으며, 부모 컴포넌트의 스타일, 이벤트 처리 등과는 독립적으로 동작한다.

Portal의 주요 사용 사례는 다음과 같다.

  • 모달 및 팝업
    react 애플리케이션 내에서 모달 창이나 팝업과 같은 UI 요소를 렌더링할 때 사용한다. 이를 통해 모달이나 팝업이 컴포넌트 트리의 특정 위치에 제한되지 않고, 애플리케이션의 다른 부분과 독립적으로 렌더링될 수 있다.

  • 툴팁
    마찬가지로 툴팁과 같이 마우스 커서와 연관된 UI 요소를 렌더링할 때 사용된다. 특정 DOM 요소와 연결된 툴팁을 효과적으로 구현할 수 있다. 모달과 툴팁 모두 overflow: hidden 이나 z-index의 css요소를 통해 시각적으로 자식을 "튀어나오도록" 보여야 하는 경우, 이들을 DOM의 다른 위치에 자식을 삽입하는 것이 유용할 수 있다.


사용법

  1. portal로 사용할 루트 작성
    알다시피 react의 모든 컴포넌트는 public/index.html<div id='root'></div> 에서 만들어진다. 하지만 Portal로 사용될 컴포넌트는 이 태그의 위치, 모양 등과 관계없이 항상 위에 그려져야하기에 Portal 전용 root element가 필요하다. 따라서 다음과 같이 <div> 를 추가해준다.
<body>
  <div id="root"></div>
  <div id="portal"></div>
</body>

  1. Portal 컴포넌트 작성
    Portal로 사용할 컴포넌트를 React.createPortal() 함수를 통해 만들어준다.
    첫번째 인자 혹은 children에는 portal에 들어간 컴포넌트가 들어가고, 두번째 인자에는 portal이 그려질 부모 element를 넣어준다.
const Portal: FC<{ children: ReactNode }> = ({ children }) => {
    const portal = document.getElementById('portal') as HTMLElement;
  
    return createPortal(children, portal);
};

  1. Portal로 띄울 컴포넌트 작성 후 대입
const PortalExample: FC = () => {
    
    return (
        <div>
            <Portal>
                <ThankyouDialog />
            </Portal>         
        </div>
    );
};

<ThankyouDialog /> 컴포넌트는 버튼을 클릭하면 모달창이 띄워지는 컴포넌트이다.
결과는 아래와 같다.


Open Modal 버튼 클릭시 아래와 같이 모달이 생성된다.


개발자 도구를 통해 DOM 요소를 확인해보면, 모달은 <div id='portal'><div> 안에 그려져 있는 것을 볼 수 있다.




또한 portal이 DOM 트리의 어디에도 존재할 수 있다 하더라도 모든 다른 면에서 일반적인 react 자식처럼 동작한다. 이는 DOM 트리에서의 위치에 상관없이 portal은 여전히 React 트리에 존재하는 것처럼 취급하기 때문이다.

이것에는 이벤트 버블링도 포함되어 있다. portal 내부에서 발생한 이벤트는 react 트리에 포함된 상위로 전파될 것이다. 즉, 쉽게 설명하자면 portal로 다른 트리로 보내놨더라도 onClick 등의 event는 root 트리에서도 적용된다는 뜻이다.


하지만 Modal이나 Popup을 작성하는 것은, 주로 UI 라이브러리에서 제공해주는 컴포넌트를 사용하는 것이 편하고 직관적인 디자인을 가지고 있다. 때문에 개발자가 직접 Portal을 작성하는 경우는 드물다.

profile
안녕하세요! 26살 프론트엔드 개발자입니다! (2024/03 ~)

0개의 댓글