티스토리 뷰
프런트엔드 프로젝트를 진행하면서 모달을 사용할 때가 너무나도 많다.
Modal의 사용성에 대해서 알아보던 중, Portal이라는 개념을 사용해서 모달을 사용하는 경우를 알게 되었다.
그래서 Portal이 어떤 것이고, 실제로 Portal을 활용해서 Modal까지 만들어 보았다.
Portal
Portal을 들었을 때, 처음 드는 생각은 약간 순간이동 이런 건가? 하는 생각이 들었다.
React 공식 문서에 따르면 Portal이란 상위 DOM 계층 외부에 존재하는 DOM 노드로 자식 컴포넌트를 랜더링 시키는 방법이라고 정의되어있다.
ReactDOM.createPortal(child, container)
첫 번째 인자로는 Child (자식 컴포넌트) 요소가 들어가고, 두 번째 인자로는 자식 컴포넌트가 담길 상위 외부 DOM 요소가 담긴다.
Portal을 사용하는 이유
Portal을 사용하면 어떤 이점이 있을까.
일반적으로 우리가 Modal을 제작하는 방법은 모달의 on/off 상태를 관리하고, 그에 따라서 현재 컴포넌트 위에 모달이 화면을 덮게 되는 형식으로 제작한다.
같은 tree에 위치하게 되기 때문에 모달이 화면을 덮고 있더라도 다른 컴포넌트의 영향을 받게 된다.
뿐만 아니라 모달의 상위 컴포넌트까지 모두 덮는 스타일링이 필요하기 때문에 z-index 부분에서도 신경을 써야 한다.
정리하자면 Portal을 사용하면 우리가 원하는 곳에서 컴포넌트가 랜더링 될 수 있기 때문에, 현재 컴포넌트와 다른 트리에 컴포넌트를 등장시킴으로써 서로 영향을 최대한 받지 않도록 하기 위해서 사용한다.
실습
공식문서의 용법으로 실제 Portal을 통해 modal을 만들어보자
먼저 4가지 file에 코드라인을 작성해 줄 것이다.
index.html
ModalWithPortal.tsx
Potal.tsx
Modal.tsx
index.html
index, html에서는 모달을 띄워줄 상위 DOM 요소의 위치를 미리 결정해 둔다.
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="portal"></div>
</body>
기존 컴포넌트들이 위치할 root 이외에 portal이라는 공간을 지정해준다.
Modal.tsx
모달 컴포넌트는 기존에 만들던 대로 제작해 주었다.
import React from 'react';
//import styled-component code
import * as S from './style';
interface Props {
onClose: () => void;
}
function Modal({ onClose }: Props) {
return (
<S.ModalBackground>
<S.ModalWrapper>
<p>Modal is Open!!!</p>
<button onClick={() => onClose()}>OK</button>
</S.ModalWrapper>
</S.ModalBackground>
);
}
export default Modal;
Portal.tsx
import { createPortal } from 'react-dom';
interface Props {
isOpen: boolean;
}
const MordalPortal: React.FC<Props> = ({ isOpen, children }) => {
if (!isOpen) return null;
return createPortal(
<div>
<div>{children}</div>
</div>,
document.querySelector('#portal') as Element,
);
};
export default MordalPortal;
위에서 설명한 용법에 따라서 자식 요소(첫 번째 인자)를 index.html에서 작성해놓은 portal에서(2번째 인자) 랜더링 되도록 한다.
ModalWithPortal.tsx
import React, { useState } from 'react';
import * as S from './style';
import ModalPortal from './Portal';
import Modal from './Modal';
function ModalWithPortal() {
const [modalIsShow, setModalIsShow] = useState<boolean>(false);
const modalControl = () => {
setModalIsShow(!modalIsShow);
};
return (
<S.PortalWrapper>
<ModalPortal isOpen={modalIsShow}>
<Modal onClose={modalControl} />
</ModalPortal>
<S.ModalButton onClick={modalControl}>Modal On</S.ModalButton>
</S.PortalWrapper>
);
}
export default ModalWithPortal;
마지막으로 모달을 사용하는 곳에서 앞서 선언한 Portal 컴포넌트로 Modal을 감싸줌으로써 Portal의 첫 번째 인자인 자식 요소가 Modal을 향하게끔 하면 된다.
위와 같이 코드를 작성하면 모달을 클릭했을 때 다음과 같이 결과를 확인할 수 있다.
#Reference
'Vue&React' 카테고리의 다른 글
[React] React.FC<> (0) | 2022.07.11 |
---|---|
[React] Redux-Thunk로 비동기로직 처리하기 (0) | 2022.05.16 |
Context API (0) | 2022.04.27 |
Vuex - (2) (0) | 2022.04.26 |
Vuex - (1) (0) | 2022.04.26 |
- Total
- Today
- Yesterday
- clean code
- AxiosInterceptor
- SOAP API
- 백준
- Vuex
- python
- 파이썬
- Vue
- redux-thunk
- redux
- js
- 알고리즘
- 상호평가
- v-for
- TypeScript
- 프로그래머스
- programmers
- error
- React.memo
- bundler
- Repository Pattern
- React
- Transpiler
- GraphQL
- SPA
- Preloading
- Vue.js
- 문제풀이
- reactrouter
- webpack
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |