사용자가 form에서 잘못된 제출을 했을 때 modal을 띄워주는 컴포넌트를 만들어보자.
import Card from './Card';
import Button from './Button';
import classes from './ErrorModal.module.css';
const ErrorModal = (props) => {
return (
<div>
<div className={classes.backdrop} onClick={props.onConfirm} />
<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>
</div>
);
};
export default ErrorModal;
위의 코드가 잘못됐다고는 할 수 없다. 하지만 이상적인 코드가 아닌 것은 분명하다. 왜냐하면 modal은 페이지 전체를 덮기 때문에 가장 바깥에 있는 것이 구조적으로는 맞기 때문이다.
이러한 상황에서 저 모달을 가장 바깥으로 즉, 원하는 위치로 보낼 수 있는 기능을 가진 것이 createPortal 메서드이다.
ReactDOM.createPortal(child, container);
createPortal 메서드를 사용해 수정하면 아래와 같다.
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 Overlay = (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 (
<>
{ReactDOM.createPortal(
<Backdrop onConfirm={props.onConfirm} />,
document.getElementById('backdrop')
)}
{ReactDOM.createPortal(
<Overlay
title={props.title}
message={props.message}
onConfirm={props.onConfirm}
/>,
document.getElementById('overlay')
)}
</>
);
};
export default ErrorModal;