본문 바로가기
Frontend/React

React Portals 개념과 사용법

by Forsaken Developer 2023. 1. 21.
728x90
728x90

React Portals 개념과 사용법

return (
    <React.Fragmentr>
      <Modal/>
      <Component/>
    </React.Fragment>
  );

이 코드에서는 좋지 않은게 하나 있는데 바로 모달이다. DOM에 렌더링되는 모달은 엄밀히 말하면 작동은 한다. 제대로 스타일링 하기만 하면 모달처럼 보일 것이다.

그러나 의미적인 관점이나 간결한 HTML 구조를 갖췄는지의 관점으로 보면 별로 좋지 않다.

왜냐하면 기본적으로 모달은 페이지 위에 표시되는 오버레이이기 때문이다.

모달은 전체 페이지에 대한 오버레이이고 따라서 다른 모든 것 위에 있다.

때문에 스타일링이나 접근성의 관점에서 문제가 생길 수 있다.

예를 들어 스크린 리더가 렌더링되는 HTML 코드를 해석할 때 이걸 일반적인 오버레이라고 인식하지 못할 수도 있다.

따라서 이 모달이 다른 모든 내용에 대한 오버레이인지 명확하지 않다.

이것은 모달의 경우에만 해당되는 것이 아니라 Drawer나 Dialog와 같은 모든 종류의 오버레이나 관련 컴포넌트에서 일어날 수 있다.

애플리케이션은 작을 때는 문제가 없지만 규모가 큰 애플리케이션에서는 컴포넌트가다른 컴포넌트 안에 깊이 중첩되어 있기도 하며 backdrop과 모달 또한 깊이 중첩된다.

이러한 문제점을 Portal로 해결할 수 있다.

즉 backdrop과 modal을 body의 직계 자식이 되도록 만들 수 있다.

portal에는 렌더링할 React의 요소와 컴포넌트를 이동시킬 곳이 필요하다.

먼저 body 태그의 아래에 backdrop과 modal을 렌더링할 루트 요소를 만든다.

<body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="backdrop-root"></div>
    <div id="overlay-root"></div>
    <div id="root"></div>
  </body>

react-dom으로 부터 ReactDom을 import 한 후 ReactDom의 createPortal 메소드를 호출할 수 있다.

createPortal 메소드는 두 개의 인수를 취하는데 첫 번째는 렌더링되어야 하는 리액트 노드이고 두 번째 인수는 이 요소가 렌더링되어야 하는 실제 DOM의 컨테이너를 가리키는 포인터이다.

이를 위해 DOM API의 document.getElementById를 사용할 수 있다.

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>
  );
};

포털의 핵심은 렌더링된 HTML 내용을 다른 곳으로 옮기는 것이다. 이전과 마찬가지로 Modal을 사용할 수 있다.

이것이 바로 포털의 장점이다. 컴포넌트를 사용하는 곳에서 createPortal을 사용하여 해당 컴포넌트의 HTML 내용을 다른 곳으로 이동시킬 수 있다. JSX에서는, 즉 컴포넌트에서는 이전과 마찬가지 방식으로 해당 컴포넌트를 계속 사용할 수 있고 다만 렌더링되는 실제 DOM 안에서 HTML 내용을 다른 곳으로 이동시킬 수 있다.

728x90
반응형

'Frontend > React' 카테고리의 다른 글

React Side Effects와 useEffect  (0) 2023.01.24
React useRef 개념 및 사용법  (2) 2023.01.22
React Fragments 개념과 사용법  (0) 2023.01.20
Props와 Children  (0) 2023.01.06
React와 JSX  (0) 2023.01.05

댓글