ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Portals
    Note 2021. 8. 30. 14:22

    Portals

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

    by React

     

    사이트를 구성하다 보면 모달이나 다이얼로그, 툴팁 같이 DOM 상에서도 최상단에 위치시켜 화면 위로 튀어나오도록 보여야 하는 경우가 있다.

     

    그러나 리액트 기본 설정으로 구성하면 볼 수 있는 ReactDOM.render() 함수로 인해 모달이나 다이얼로그 등은 언제나 root의 자식 요소로 배치되게 되는데, 이때 포탈(portal)을 활용하면 부모 요소 바깥에 컴포넌트를 렌더링 할 수 있게 된다.

    // index.js
    
    ReactDOM.render(<App />, document.getElementById('root'));

     

    Portal을 통한 이벤트 버블링

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

    by React

     

    Portals 사용법

     

    CRA로 프로젝트를 만들면 public 폴더의 index.html 파일에 기본적으로 아래와 같이 작성되어 있다. 이때 #root는 일반적으로 내가 작성한 App 컴포넌트가 렌더링 되는 곳이다. 여기에 형제 노드인 #modal을 만들어 Modal 컴포넌트를 렌더링 할 위치를 잡아준다.

    <html>
    ...
      <body>
        <div id="root"></div>
        <div id="modal"></div> // 추가
      </body>
    </html>

     

    리액트의 createPortal을 호출하여 Portal을 생성할 수 있다.

    ReactDOM.createPortal(child, container)

    createPortal의 첫 번째 인자인 child는 요소, 문자열 또는 Fragment와 같은 렌더링이 가능한 React의 하위 요소,

    두 번째 container는 DOM 요소를 말한다.

     

    간단한 모달을 만들어보자.

    export default function Modal({ children, onClose }) {
      return ReactDom.createPortal(
        <div className="modal">
          <div className="contents">
            <h2>모달</h2>
            {children}
            <button onClick={onClose}>닫기</button>
          </div>
        </div>,
        document.getElementById("modal")
      );
    }

     

    이제 모달을 사용하고 싶은 컴포넌트에 추가해보자.

    export default function App() {
      const [showModal, setShowModal] = useState(false);
    
      const openModal = () => {
        setShowModal(true);
      };
    
      const closeModal = () => {
        setShowModal(false);
      };
    
      return (
        <div className="App">
          <h2>React Portals</h2>
          <button onClick={openModal}>열기</button>
          {showModal && (
            <Modal onClose={closeModal}>
              <p>모달이 열렸습니다!!</p>
            </Modal>
          )}
        </div>
      );
    }

     

     

    분명 다른 DOM 트리(#App, #modal) 렌더링 되었는데 state가 바뀌고 이벤트가 정상적으로 동작하는 것을 확인할 수 있다. 리액트 공식 문서에 나와있듯이 portal 내부에서 발생한 이벤트는 React 트리에 포함된 상위로 전파되는 것이다. DOM 트리에서는 그 상위가 아니라 하더라도 말이다.

     

    portal에서 버블링 된 이벤트를 부모 컴포넌트에서 포착한다는 것은 본질적으로 조금 더 유연한 개발이 가능함을 나타내는 것이다.

     

     

     

     

     

     

     

     

     

     

     

     

     

    'Note' 카테고리의 다른 글

    webpack  (0) 2021.09.09
    Context API  (0) 2021.09.03
    옵셔널 체이닝  (0) 2021.08.24
    자바스크립트 클린 코드  (0) 2021.08.21
    이벤트 루프  (0) 2021.08.13

    댓글