React에는 React-Modal 이라는 라이브러리가 존재한다. 그런데 사용법을 익히기도 귀찮았고(무엇보다 문서가 없었다), CSS 적용하기도 어려워서 그냥 직접 만들기로 했다. 생각보다 어려운 작업이 아니었다. 약간의 CSS 지식만 있다면 빠르게 구현할 수 있을 정도의 수준이지만, 이번 게시글에선 그 조차도 쉽게 설명해서 모두가 이해하도록 해보겠다.
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Main from './components/main';
import './index.css';
ReactDOM.render(
<React.StrictMode>
<Main />
</React.StrictMode>,
document.getElementById('root')
);
App.js 사용하지 않았다. 대신 Main.js를 따로 만들어서 이를 최상위 컴포넌트로 사용했다.
Main.js
import React, { useEffect, useState } from 'react';
import AddRoomModal from './AddRoomModal/index';
import BodyContent from './MessageList/index';
import styles from './main.module.css';
import Navbar from './Navbar/index';
function Main () {
const [isModal, setIsModal] = useState(false);
return (
<div className={styles['content']}>
<Navbar setIsModal={setIsModal} />
<BodyContent />
<AddRoomModal isModal={isModal} setIsModal={setIsModal} />
</div>
);
}
export default Main;
.content {
width: 100vw;
height: 100vh;
display: flex;
position: relative;
}
구현한 Modal은 화면 전체를 덮는 형태이다. 따라서 최상위 컴포넌트인 Main.js에 위치시켰다. 그리고 최상위 div 영역에 position: relative; 옵션을 추가했다. 그렇지 않으면 Modal 컴포넌트가 화면 위에 생기는게 아니라 화면 아래에 붙어서 생기게된다.
AddRoomModal.js
import React from 'react';
import styles from './index.module.css';
function AddRoomModal (props) {
const [isModal, setIsModal] = [props.isModal, props.setIsModal];
function onClickClose () {
setIsModal(false);
}
function onClickCreate () {
// ...
setIsModal(false);
}
return (
<div className={(isModal) ? styles['modal'] : styles['close']}>
<section>
<header>
<div>Create a Room</div>
<button onClick={onClickClose}>X</button>
</header>
<main>
<div>
<div>Room Name</div>
</div>
<div>
<div>Member</div>
<select disabled></select>
</div>
</main>
<footer>
<button className={styles['btn-left']} onClick={onClickCreate}>Create</button>
<button className={styles['btn-right']} onClick={onClickClose}>Close</button>
</footer>
</section>
</div>
);
}
export default AddRoomModal;
.close {
display: none;
animation: modal-close 0.3s;
}
.modal {
z-index: 10;
width: 100%;
height: 100%;
position: absolute;
animation: modal-show 0.3s;
background-color: rgba(0, 0, 0, 0.6);
}
.modal > section {
width: 30%;
height: 40%;
margin-top: 15%;
margin-left: 35%;
border-radius: 0.5rem;
background: #f2f2f2;
}
.modal > section > header {
width: 100%;
height: 20%;
display: flex;
font-size: 20px;
font-weight: bold;
position: relative;
background-color: #D3D3D3;
border-top-left-radius: 0.5rem;
border-top-right-radius: 0.5rem;
border-bottom: 1px solid #D3D3D3;
}
.modal > section > header > div {
width: 80%;
padding-left: 5%;
line-height: 74.16px;
}
.modal > section > header > button {
width: 20%;
border: 0px;
transition: 0.3s;
line-height: 74.16px;
background-color: #D3D3D3;
border-top-right-radius: 0.5rem;
}
.modal > section > header > button:hover {
cursor: pointer;
background-color: #838282;
}
.modal > section > main {
height: 60%;
width: 100%;
border-bottom: 1px solid #D3D3D3;
}
.modal > section > main > div {
width: 100%;
height: 50%;
display: flex;
text-align: center;
}
.modal > section > main > div > div{
width: 30%;
font-size: 15px;
font-weight: bold;
margin-top: 10%;
}
.modal > section > main > div > input {
width: 60%;
height: 20%;
border: 0px;
margin-top: 7%;
padding-left: 15px;
border-radius: 0.5rem;
transform: translateY(50%);
}
.modal > section > main > div > select {
width: 40%;
height: 20%;
border: 0px;
margin-top: 7%;
border-radius: 0.5rem;
transform: translateY(60%);
}
.modal > section > footer {
height: 20%;
padding-right: 5%;
text-align: right;
line-height: 74.95px;
}
.btn-left {
border: 0px;
width: 70px;
height: 40px;
font-size: 12px;
transition: 0.3s;
font-weight: bold;
background-color: #D3D3D3;
border-top-left-radius: 0.5rem;
border-bottom-left-radius: 0.5rem;
}
.btn-left:hover, .btn-right:hover {
cursor: pointer;
background-color: #838282;
}
.btn-right {
border: 0px;
width: 70px;
height: 40px;
font-size: 12px;
transition: 0.3s;
font-weight: bold;
background-color: #D3D3D3;
border-top-right-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
}
@keyframes modal-show {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes modal-close {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
Modal 영역에서 중요한 것은 position: absolute 과 z-index: 10 을 적용해줘야만 한다는 것이다. 그렇지 않으면 위에서 설명한 내용과 마찬가지로 모달 영역이 화면 위로 생기는 것이 아닌, 화면 아래에 붙어서 다른 방식으로 보이게된다. 그 외에 Modal이 꺼진 상태 와 Modal이 켜진 상태 를 분기처리하기 위해 display: none 으로 CSS를 분기처리했다. 그리고 Modal 상태를 체크하기 위한 변수를 useState로 정의 하였고, 버튼 클릭에 따라 setting 함수를 통해 모달 상태 여부를 ON/OFF 처리 시켰다.
생각보다 간단한 기능이라 금방 구현했다. 오히려 React-Modal 라이브러리 사용하려고 찾아보고 공부하려다가 낭비한 시간이 더 아까울 정도였다. 천천히 차근차근 읽어보면 금방 이해할 수 있으니 시도해보길 바란다.
'Programming > Javascript' 카테고리의 다른 글
[Tip] 구글 애드센스(AdSense) Height Auto Important 강제 적용 해제 (0) | 2024.01.27 |
---|---|
[JS] 순열 / 중복순열 / 조합 / 중복조합 (0) | 2022.08.10 |
[React] 컴포넌트(Component) Fade In/Fade Out 구현 (0) | 2022.08.03 |
[React] 'react-scripts'은(는) 내부 또는 외부 명령 실행할 수 있는 프로그램, 또는 배치 파일이 아닙니다. (0) | 2022.08.03 |
[Javascrit] 정규표현식 (Regular Expression) 정리 (0) | 2022.07.27 |
댓글