그럼에도 불구하고

👨‍💻

[React] Portal이란? 본문

React/React basics

[React] Portal이란?

zenghyun 2023. 4. 6. 22:13

오늘은  Portal에 대해 알아보겠습니다. :)

 

 

 

[ Portal ] 

React 공식 문서에 따르면

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

 

 

현재 <div id ="root"><div class="ErrorModal_backdrop__iw-9R">은 부모 자식 관계로 속해있습니다.

 

 

[  사용 이유  ]

위키백과 - 트리 구조

 

일반적으로 react는 부모 컴포넌트가 렌더링 되면 자식 컴포넌트가 렌더링 되는 tree 구조를 가지고 있습니다.

하지만 때때로 이런 tree구조가 불편함을 가져다주기도 해서, 

이럴 때 부모-자식 관계를 유지하지만 독립적인 위치에서 렌더링을 하면 훨씬 편리한 경우가 있습니다.

 

대표적인 예로 modal은 부모 컴포넌트의 스타일링 속성에 제약을 받아 z-index 등으로 번거로운 후처리를 해줘야합니다.

 

이러한 상황에서 portal 통해 독립적인 구조와 부모-자식 관계를 동시에 유지할 있다면, z-index 부모 컴포넌트의 제약에서 벗어날 있습니다.

 

[ 구현 방법 ]

1. public/index.html Modal 렌더링 위치 심어주기

 

1
2
3
4
5
<body>
    <div id="backdrop-root"></div>
    <div id="overlay-root"></div>
    <div id="root"></div>
 </body>
cs

 

portal을 구현할 tree의 부모 컴포넌트를 어디로 설정할지 정하는 것입니다.
위 코드에선 기존 최상단 요소인 root의 형제관계로 backdrop과 modal 요소를 넣었습니다.
이 요소에서 backdrop과 modal 컴포넌트가 렌더링 되도록 만들 예정입니다.

 

2. ErrorModal.js에서import reactDom from "react-dom" 설정하기

 

1
import ReactDOM from "react-dom";
cs

 

3. ErrorModal.js에서 Backdrop div 만들기 

 

1
2
3
const Backdrop = (props) => {
  return <div className={classes.backdrop} onClick={props.onConfirm} />;
};
cs

 

4. ErrorModal.js에서ModalOverlay 만들기

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const ModalOverlay = (props) => {
  return (
    <Card className={classes.modal}>
      <header className={classes.header}>
        <h2>{props.title}</h2>
      </header>
      <div className={classes.content}>
        <p>{props.message}</p>
      </div>
      <footer className={classes.actions}>
        <Button onClick={props.onConfirm}>Okay</Button>
      </footer>
    </Card>
  );
};
cs

만들던 파일에서 가져온 코드라 만드는 방식만 보시면 됩니다. :)

 

 

5. Backdrop, Modal을 띄울 컴포넌트에 Portal, Backdrop, Modal 조건부 렌더링 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const ErrorModal = (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>
  );
};
cs

 

backdrop와 modal을 렌더링 하고자 하는 컴포넌트 파일에서 Portal에 감싸진 형태로 backdrop과 modal을 넣어주면 됩니다.

 

물론 backdrop과 modal의 경우 계속 UI에 나타나면 안 되기에 다른 파일에서 마우스로 클릭 시 이를 제어할 수 있게 만들어줬습니다. 

 

 

 

참고용 전체 코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import React from "react";
import ReactDOM from "react-dom";
 
import Card from "./Card";
import Button from "./Button";
import classes from "./ErrorModal.module.css";
 
const Backdrop = (props) => {
  return <div className={classes.backdrop} onClick={props.onConfirm} />;
};
 
const ModalOverlay = (props) => {
  return (
    <Card className={classes.modal}>
      <header className={classes.header}>
        <h2>{props.title}</h2>
      </header>
      <div className={classes.content}>
        <p>{props.message}</p>
      </div>
      <footer className={classes.actions}>
        <Button onClick={props.onConfirm}>Okay</Button>
      </footer>
    </Card>
  );
};
 
const ErrorModal = (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 ErrorModal;
 
cs

 

 

 

 

backdrop과 modal이 root와 분리되어 있는 것을 볼 수 있습니다. 

 

 

ref: React 공식 문서 - Portals

       https://jeonghwan-kim.github.io/2022/06/02/react-portal

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

[React] useEffect란?  (0) 2023.04.07
[React] useRef란?  (0) 2023.04.06
[React] htmlFor란?  (0) 2023.04.06
[React] Styled Component란?  (0) 2023.04.04
[React] state란?  (0) 2023.03.29
Comments