CreatePortal이란?

createPortal – React

createPortal일부 하위 요소를 DOM의 다른 부분을 렌더링 할 수 있습니다.

<div>
  <SomeComponent />
  {createPortal(children, domNode, key?)}
</div>

<aside> 💡 포털은 DOM 노드의 물리적 배치만 변경합니다. 다른 모든 방법으로 포털에 렌더링하는 JSX는 이를 렌더링하는 React 구성 요소의 하위 노드 역할을 합니다. 예를 들어, 자식은 부모 트리에서 제공하는 컨텍스트에 액세스할 수 있으며, 이벤트는 React 트리에 따라 자식에서 부모로 버블링됩니다.

</aside>

1. DOM의 다른 부분으로 렌더링(모달 구현 가능)

포털을 사용 하면 구성 요소가 일부 하위 항목을 DOM의 다른 위치에 렌더링할 수 있습니다. 이를 통해 구성 요소의 일부가 어떤 컨테이너에 있든 "이스케이프"할 수 있습니다. 예를 들어 구성 요소는 페이지의 나머지 부분 위와 외부에 나타나는 모달 대화 상자나 도구 설명을 표시할 수 있습니다.

<aside> 💡 포털을 생성하려면 JSX 와 DOM 노드를 createPortal사용하여 결과를 렌더링해야 합니다 .

</aside>

import { createPortal } from 'react-dom';

function MyComponent() {
  return (
    <div style={{ border: '2px solid black' }}>
      <p>This child is placed in the parent div.</p>
      {createPortal(
        <p>This child is placed in the document body.</p>,
        document.body
      )}
    </div>
  );
}

포털이 없으면 두 번째 포털은 <p>상위 내부에 배치되지만 <div>포털은 포털을 다음으로 "순간 이동"했습니다 document.body.

Modal.zip

실제 활용

import React, { HTMLAttributes, useRef } from 'react';
import { createPortal } from 'react-dom';

import CloseBtn from 'assets/common/close_btn.png';
import { Modal as ModalProps } from 'features/modalSlice/types';

import * as S from './styles';

interface Props extends ModalProps, HTMLAttributes<HTMLDivElement> {}

const Modal: React.FC<Props> = ({
  children,
  size = `default`,
  isShow = false,
  title,
  isXButton = true,
  explanation,
  headerComponentExtended,
  footerComponent,
  onClose,
}) => {
  const modalRef = useRef<HTMLDivElement | null>(null);

  return createPortal(
    <S.ModalWrapper ref={modalRef}>
      <S.ModalOverlay onClick={onClose} />
      <S.ModalField modalSize={size} isShow={isShow}>
        <S.ModalHeader>
          {isXButton && (
            <S.CloseBtn onClick={onClose}>
              <img src={CloseBtn} alt="Close button" />
            </S.CloseBtn>
          )}
        </S.ModalHeader>
        <S.ModalBody>
          {title && <S.ModalTit>{title}</S.ModalTit>}
          <S.ModalExplanation>{explanation}</S.ModalExplanation>
          {headerComponentExtended}
          {children}
        </S.ModalBody>
        <S.ModalFooter>{footerComponent}</S.ModalFooter>
      </S.ModalField>
    </S.ModalWrapper>,
    document.body,
  );
};

export default Modal;