React

[React] Portals, createPortal

ssohyunn 2023. 9. 14. 15:06
return (
  <>
    <Modal />
    <InputForm />
  </>
);

위 컴포넌트를 예를 들어보면, 실제 DOM에 들어가는 내용은 아래와 같을 것이다.

<section>
  <div className='backdrop' />
  <div className='modal'>
    <div className='content'>
      <p>{props.message}</p>
    </div>
  </div>
  
  <form>
   ...
  </form>
</section>

이 코드는 잘 동작하지만 의미적인 관점에서 좋지 않다.

모달전체 페이지 위에 표시되는 오버레이이다. 따라서 다른 모든 것 위에 있어야 하는 것이 맞다.

하지만 이 코드는 다른 HTML 코드 안에 중첩되어 있기 때문에 좋은 코드가 아니다.

 

 

따라서 모달이 깊게 중첩되지 않게, 다른 것들 위에 있어야 하려면 다음과 같은 구조가 맞다.

<div className='backdrop' />
<div className='modal'>
  <div className='content'>
    <p>{props.message}</p>
  </div>
</div>
<section>  
  <form>
   ...
  </form>
</section>

이처럼 렌더링하려는 HTML 내용을 다른 곳으로 이동시켜 렌더링하려면 Portal을 사용하면 된다. 

 

Portal

1. 컴포넌트를 이동시킬 장소 필요

보통 public/index.html 에서 div를 추가해 나중에 이 장소를 찾아오도록 한다.

루트를 여러 개 만들어서 여러 다른 종류의 컴포넌트들을 해당 div로 이동시킬 수 있다.

 

2. 리액트에게 실제로 어딘가로 포탈되어야 한다고 알려준다.

createPortal 메서드는 react-dom 라이브러리에 정의되어 있다.

import { createPortal } from 'react-dom';

or

import ReactDOM from 'react-dom';
// 사용-> ReactDOM.createPortal

createPortal의 인수로는 렌더링할 리액트 노드를 전달해주고(JSX여야 한다.), 

두 번째 인수로는 첫 번째 인수의 컴포넌트가 렌더링되어야 하는 DOM의 컨테이너를 가리키는 포인터(DOM 노드)를 전달해주면 된다.

 

 

const Modal = (props) => {
  return (
    <React.Fragment>
      {ReactDOM.createPortal(
        <Backdrop onConfirm={props.onConfirm} />,
        document.getElementById('backdrop-root')
      )}
      {ReactDOM.createPortal(
        <ModalOverlay
          title={props.title}
          message={props.message}
          onConfirm={props.onConfirm}
        />,
        document.getElementById('overlay-root')
      )}
    </React.Fragment>
  );
};


export default Modal;
createPortal을 사용해 렌더링된 HTML 내용을 다른 곳으로 이동시킨다.