react.js
[react 리액트] Portal 을 사용하여 모달창 만들기
코복이
2023. 6. 28. 19:09
728x90
1. Portal 은 부모 컴포넌트 DOM 계층 구조 밖으로 자식을 랜더링한다
모달의 위치는 어떤 것에도 간섭받지 않는 root 밖으로 와야 한다.
id 값으로 포탈 위치를 정할 수 있는데, 위치는 root에 간섭받지 않도록 root와 형제자리로 한다.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<!-- 모달이 올 위치는 root와 형제자리 -->
<div id="overlays"></div>
<div id="root"></div>
</body>
</html>
2. 모달 컴포넌트에서 ReactDOM을 호출하고 CratePortal 메소드를 실행한다.
Modal.js
(모달 컴포넌트 = 현재 코드에선 모달 '프레임'으로 이제 이걸로 원하는 컴포넌트를 감싸면 됨)
import { Fragment } from "react";
import ReactDOM from "react-dom";
import styles from "./Modal.module.css";
/* Backdrop, ModalOverlay는 모달 디자인 컴포넌트 */
// 뒷배경
const Backdrop = () => {
return <div className={styles.Backdrop}></div>;
};
// 모달창 ({props.children}으로 감쌀 내용을 가져와야 함)
const ModalOverlay = (props) => {
return (
<div className={styles.modal}>
<div className={styles.content}>{props.children}</div>
</div>
);
};
/* index.html에서 모달을 만들기 위해 추가한 overlay에 접근 */
const portalElement = document.getElementById("overlays");
/* ReactDOM.createPortal() 메소드는 두개 인자를 받음 (포탈 위치로 보낼 것, 포탈 위치) */
// Fragment는 <></> 빈배열과 동일
export default function Modal(props) {
return (
<Fragment>
{ReactDOM.createPortal(<Backdrop />, portalElement)}
{ReactDOM.createPortal(
<ModalOverlay>{props.children}</ModalOverlay>,
portalElement
)}
</Fragment>
);
}
3. boolean 타입의 useState로 스위치 껐다켰다 구현해주면 끝.
import React, { Fragment, useState } from "react";
import Header from "./Components/Layout/Header";
import Meals from "./Components/Meals/Meals";
import Cart from "./Components/Cart/Cart";
function App() {
/* setter 함수에 true가 들어가면 Modal 켜지고 false가 들어오면 꺼짐 */
const [cardIsShown, setCardIsShown] = useState(false)
const handleShowCard = () => {
setCardIsShown(true)
}
const handleHideCard = () => {
setCardIsShown(false)
}
return (
<Fragment>
{cardIsShown && <Cart handleHideCard={handleHideCard}/>}
<Header handleShowCard={handleShowCard} />
<main>
<Meals />
</main>
</Fragment>
);
}
export default App;
4. 완성


728x90