React createPortal 완벽 가이드

React createPortal 완벽 가이드

React의 createPortal은 컴포넌트를 현재의 React 컴포넌트 계층 구조와는 다른 DOM 트리에 렌더링할 수 있도록 해주는 강력한 API입니다.


createPortal이란?

기본적으로 React 컴포넌트는 부모 컴포넌트의 DOM 트리에 자식으로 렌더링됩니다. 하지만 모달, 툴팁, 알림과 같은 특정 UI 요소는 스타일 충돌과 z-index 문제를 피하기 위해 DOM 구조 밖에서 렌더링될 필요가 있습니다.

createPortal은 이러한 UI 요소를 React 컴포넌트 계층 구조를 유지하면서도 다른 DOM 노드에 렌더링할 수 있도록 도와줍니다.

문법

ReactDOM.createPortal(child, container)
  • child: 렌더링할 React 엘리먼트나 컴포넌트입니다.
  • container: child를 렌더링할 대상 DOM 엘리먼트입니다.

createPortal을 사용하는 이유

1. 스타일 충돌 방지

모달과 같은 컴포넌트는 부모 요소의 스타일(예: overflow: hidden)에 영향을 받을 수 있습니다. 별도의 DOM 노드에 렌더링하면 이러한 문제를 방지할 수 있습니다.

2. React 트리 통합 유지

컴포넌트가 다른 DOM 트리에 렌더링되더라도 React의 상태와 이벤트 흐름은 정상적으로 유지됩니다.

3. 사용자 경험 개선

createPortal을 사용하면 레이아웃과 스타일 제약 없이 UI 요소를 구축할 수 있어 더욱 매끄러운 사용자 경험을 제공합니다.


주요 특징 및 동작 원리

이벤트 버블링

포털 내부에서 발생한 이벤트는 React 컴포넌트 트리를 통해 전파됩니다. 따라서 React의 이벤트 시스템이 방해받지 않습니다.

예제:

const Modal = ({ children }) => {
  const modalRoot = document.getElementById('modal-root');

  return ReactDOM.createPortal(
    <div className="modal" onClick={() => console.log('Modal clicked')}>
      {children}
    </div>,
    modalRoot
  );
};

const App = () => (
  <div onClick={() => console.log('App clicked')}>
    <h1>React Portal Example</h1>
    <Modal>
      <button>Click Me</button>
    </Modal>
  </div>
);

출력:

  • 모달 버튼 클릭 시 "Modal clicked"와 "App clicked"가 모두 출력됩니다. (이벤트 버블링)

실용적인 활용 사례

1. 모달

중요한 메시지 표시나 사용자 입력을 받는 UI 요소.

2. 툴팁

부모 컨테이너 스타일의 제약 없이 컨텍스트 정보를 제공.

3. 드롭다운

스크롤이나 부모 요소의 잘림(clipping) 문제 없이 동작하는 메뉴 구현.

4. 알림

전역적으로 표시되는 알림을 DOM의 루트에 렌더링.


구현 예제

포털을 이용한 모달 컴포넌트

import React, { useState } from "react";
import ReactDOM from "react-dom";

const Modal = ({ isOpen, onClose, children }) => {
  if (!isOpen) return null;

  const modalRoot = document.getElementById("modal-root");

  return ReactDOM.createPortal(
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal-content" onClick={(e) => e.stopPropagation()}>
        {children}
      </div>
    </div>,
    modalRoot
  );
};

const App = () => {
  const [isModalOpen, setModalOpen] = useState(false);

  return (
    <div>
      <h1>React `createPortal` Example</h1>
      <button onClick={() => setModalOpen(true)}>Open Modal</button>
      <Modal isOpen={isModalOpen} onClose={() => setModalOpen(false)}>
        <h2>Modal Content</h2>
        <button onClick={() => setModalOpen(false)}>Close</button>
      </Modal>
    </div>
  );
};

export default App;

HTML 구조

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

모달 CSS

.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
}

.modal-content {
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

결론

React의 createPortal은 모달, 툴팁, 알림과 같은 유연하고 강력한 UI 컴포넌트를 구현하는 데 필수적인 API입니다. 이를 통해 DOM 계층 구조의 제약 없이 컴포넌트를 렌더링하면서도 React의 상태 및 이벤트 관리를 유지할 수 있습니다.

createPortal의 사용법과 사례를 이해하고 적절히 활용하여, 사용성 높은 웹 애플리케이션을 개발해 보세요.