React portal

Sharlotte ·2023년 1월 8일
2

Project D

목록 보기
3/3

Portal

리액트 포탈은 리액트 공식 문서의 고급 안내서에 기제된 API 중 하나다.

Portal은 부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링하는 최고의 방법을 제공합니다.
https://ko.reactjs.org/docs/portals.html

왜 Portal인가

처음 Dialog를 구현할 땐 root DOM 컨테이너 안에서 엘리먼트를 렌더링하려 했다. 여러 Dialog의 렌더링을 동시다발적으로 이루기 위해선 Dialog를 보여주고 숨겨주는 기능을 담당할 singleton Manager가 필요하다고 생각했고, 곧바로 이행했지만 좀처럼 만족스러운 코드와 결과가 나오지 못했다. libGDX처럼 리액트의 특수한 가상 돔 시스템이 없는 곳에선 괜찮은 구조였을진 몰라도 이 가상 돔의 환경에선 다르게 적용해야 하는 것이다.

Portal은 여러가지 강점을 지니는데, 일단

  • 그 성질 자체가 메인 돔 트리와의 여러가지 부작용을 사전에 방지
    • CSS의 상속 스타일링
    • 가상 돔의 개발자가 예기치 못한 재랜더링
  • 매우 간편한 적용 방법
  • 컴포넌트의 유연한 제어

그래서 Manager는 Portal보다 좋지 않다.

이 Manager 구조가 잘못되고, 작동하지 않는다는 말이 아니다. 다만 Portal을 적용하면 Manager가 불필요하기 때문에 그 가독성과 양적인 면에서 Portal가 우위를 점한다는 말이다.

Manager는 Dialog 컴포넌트들을 자식들로부터 받아 일괄적으로 랜더링하는 구조를 가지고 있다. 이러한 Manager는 Portal의 장점과 완벽히 상반된 모습을 띄고 있다.

  • Manager는 루트 돔 컨테이너에 속해있기 때문에 예기치 못한 부작용을 받을 수 있다.
  • Manager가 랜더링하게끔 하려면 고려해야 하는 요소가 최소 3가지로 정말 많다.
  • Manager가 모든 Dialog 컴포넌트를 저장하여 일괄적으로 랜더링하기 때문에 컴포넌트의 유연한 제어는 바랄 수 없다.

마치 Portal는 이러한 Manager의 문제를 겪은 개발진들이 만들어낸 혜안과 같이 느껴졌다.

어떻게 적용하는가

공식 문서에선 더 정확하고 확장적인 주제를 다루기 위해 CC를 통해 설명하지만 매우 단순하게 정리하자면 아래와 같다.

  1. 루트, 즉 index.html에서 root 엘리먼트와 같은 위치에 루트 엘리먼트를 만든다.
  1. 생성한 div 엘리먼트를 가져와서 새 div 엘리먼트를 만든 뒤 루트 엘리먼트에 추가한다.
  1. 컴포넌트의 랜더링 위치에서 ReactDOM.createPortal(children, container) api 함수로 포탈을 생성하여 반환한다.
    첫번째 인자는 포탈의 자식, 두번째 인자는 포탈이다. modal-root는 포탈을 생성하기 위한 좌표인 셈이다. ReactDOM는 react-dom에서 default로 가져온다.

실제로 테스트해보면 컴포넌트를 랜더링할 때마다 modal-root의 자식 div가 갱신되는 모습을 볼 수 있다.

여담

  • 사실 MUI의 자매품 컴포넌트인줄 알았는데 원산지가 리액트인 기술이였던 것에 놀라웠다. MUI를 못쓰니 Dialog Manager를 만들어야겠단 생각의 흐름으로 간건데 이리 쉬울 줄은 몰랐다.
  • 기존 Dialog 컴포넌트에 덧씌우는 모습이라 HOC나 래퍼 컴포넌트로 분리해도 좋을 것 같다.
  • 기존 Dialog 컴포넌트에 그대로 적용하기 때문에 새로운 파일이 필요 없다. Manager보다 더 나은 점이기도 하다.
profile
샤르르르

0개의 댓글