본문 바로가기
Programming/Javascript

[React] Modal 만들기 (React-Modal 사용 X)

by 8ugust 2022. 2. 26.

 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 라이브러리 사용하려고 찾아보고 공부하려다가 낭비한 시간이 더 아까울 정도였다. 천천히 차근차근 읽어보면 금방 이해할 수 있으니 시도해보길 바란다.

 

 

 

 

 

댓글