Portal을 이용한 모달창 만들기

PpOee·2022년 1월 23일
0
post-thumbnail

React Portal

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

보통 자식 컴포넌트가 부모 컨테이너 범위를 오버해서 튀어나와 보여야하는 경우에 많이 사용된다.
모달, 툴팁 등이 대표적인 예이다.
이런 UI 컴포넌트들은 상위 컴포넌트 스타일의 상속/충돌 (overflow: hidden, z-index) 같은 이슈들을 피하기 위해 앱 범위를 벗어난 곳에 위치시키는 것이 더 바람직한 경우가 있다.

이제 portal을 이용해서 모달 창을 띄워보도록 하자 😊

Portal 생성 방법

ReactDOM.createPortal(child, container)

여기서 child는 React 엘리먼트이고, container는 portal이 child를 위치시킬 DOM 엘리먼트이다.


index.html

...
<body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <div id="modal-container"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>

Modal.js

import ReactDOM from 'react-dom';
import './Modal.css';

function Modal ({ open, children }) {
  if (!open) return null;

  return ReactDOM.createPortal(
      <div className="modal">{children}</div>,
      document.getElementById('modal-container'));
}

export default Modal;

App.js

import { useState } from 'react';
import Modal from './Modal';

function App() {
  const [open, setOpen] = useState(false);

  const openModal = () => {
    setOpen(true);
  };

  const closeModal = () => {
    setOpen(false);
  };

  return (
    <div className="App">
      <button onClick={openModal}>Open Modal</button>
      <Modal open={open}>
        <div>hi! this is modal</div>
        <button onClick={closeModal}>Close Modal</button>
      </Modal>
    </div>
  );
}

export default App;

결과

Elements 탭으로 DOM 구조를 살펴보면 Modal 컴포넌트는

<div id="root"></div>

가 아닌

<div id="modal-container"></div>

의 자식 노드로 들어가 있는 것을 볼 수 있다.


그리고! 중요한 점은 portal이 DOM 트리의 어디에도 존재할 수 있다 하더라도 모든 다른 면에서 일반적인 React 자식처럼 동작한다는 점이다.
( React devtool을 통해 React components tree 구조를 보면 Modal 컴포넌트는 여전히 App 컴포넌트의 하위 컴포넌트로 위치해있다.)

portal은 여전히 React 트리에 존재하기 때문에 context와 같은 기능은 자식이 portal이든지 아니든지 상관없이 정확하게 같게 동작한다.
Modal에 close 기능이 있는데 이도 같은 맥락이다.

이벤트 버블링도 마찬가지다.
이벤트는 React 트리에 포함된 상위로 전파될 것이다.

이처럼 Portal을 통해 논리적으로 컴포넌트에 속하는 element 일부를 DOM 상에서 위치만 옮기게 할 수 있다.👍

0개의 댓글