모달창

Vorhandenheit ·2021년 11월 10일
0

React

목록 보기
12/17

모달 창 (Modal window)

스프린트 중에 모달 이라는 게 나왔는데, 이 이상한 어감의 단어는 무엇인지 궁금해졌습니다.
영어 사전에 치면 1.양식의 2.형태상의 3. 법의 ..이런 식으로 쓰이는데, 아무래도 실제 용도와 전혀 상관 없는 듯 합니다.

Modal에 대해서 위키페디아에서는 "사용자 인터페이스 디자인 개념에서 자식 윈도에서 부모 윈도로 돌아가기 전에 사용자의 상호동작을 요구하는 창을 말한다. 그래서 응용 프로그램의 주 창의 작업 흐름을 방해한다. 일반적으로 모달 대화상자로 불리는데, 그 이유는 대화상자를 부를 때 흔히 사용되기 때문이다. 우리가 자주 사용하는 파일 열기/저장 대화상자를 생각하면 이해하기 쉽다." 이렇게 묘사합니다.

주로 팝업창과 모달창을 비교할 때, 자식 윈도에서 부모 윈도로 상속에 개념에 집중하여서 비교해서 설명합니다. modal의 의미에 좀 더 가까운 것은 응용 프로그램의 주 창의 작업흐름을 방해한다에 있습니다.

한번 모달창이 열리면 (자식 페이지), 모달창이 끝날 때까지 부모페이지의 작업을 하지 못하게됩니다. 과정이 추가가 되는 것입니다.

모달 창이라고 이름이 붙은 것은 이 모달 창의 작업이 종료되기전까지 다른 작업을 하지 못하게 됩니다. 모달 창의 의미와 중요성은 여기에 있습니다. 다른 작업으로 넘어가기전에 꼭 필요한 '정보 전달'을 할 수도 있고 과정을 추가하여 필요한 데이터를 받아올 수도 있습니다.

리액트에서 모달창 만들기

  • Styled-Component 사용

부모컴포넌트

//ModalContainer.jsx
import React, { useState } from 'react'
import Modal from './Modal'


const ModalContainer = () => {
    const [modalOpen, setModalOpen] = useState(false)
    const modalClose = () => {
        setModalOpen(!modalOpen)
    }

    return (
        <>
        <button onClick={modalClose}>Click</button>
        { modalOpen && <Modal modalClose={modalClose}></Modal>}
        </> // 조건부 사용

    )
}

export default ModalContainer

button을 누르면 modalClose 함수가 발동!, modalOpen이 true값으로 반환되어진다.
그리고 Modal 컴포넌트가 실행되어진다

// Modal.jsx

import React from 'react'
import './Modal.scss'

const Modal = ({modalClose}) => {
  
  	const onCloseModal = (e) => {
        console.log('e.target: ', e.target)
        console.log('e.tarcurrentTargetget: ', e.currentTarget)
        if(e.target === e.currentTarget){
            modalClose()
        }

    }
    return (
        <div className="modal__container" onClick = {onCloseMedal}>
            <div className="modal">
                <button className="modal__button" onClick={modalClose}> Modal Close</button>
            </div>
        </div>
    )
}

export default Modal

이 부분에서 유념해서 봐야할 곳은 State 끌어올리기이다, 부모 컴포넌트에서 자식창을 여는 것까지는 됬지만 이제는 반대로 자식창에서 부모창으로 데이터를 전달해서 다시 false값으로 바꿔야합니다.
그래서 자식 컴포넌트로 {modalClose}를 전달하고 그 값을 다시 받아와야합니다.

// Modal.scss

.modal__container{
    width: 100%;
    height: 100vh;
    background-color: rgba(0,0,0,0.4);
    z-index: 10;
    position: fixed;
    top: 0;
    left: 0;

    .modal{
        width: 300px;
        height: 150px;
        background-color: #fff;
        // Modal 창 브라우저 가운데로 조정
        position: absolute;
        left: 50%;
        top:50%;
        transform: translate(-50%, -50%);
        z-index:100;

        .modal__button{
            position: relative;
            left: 50%;
            top:50%;
            transform: translate(-50%, -50%);
        }
    }
}

직접!

버튼을 눌렀을 때 모달창을 켜고, 끄는 것 까지는 아무래도 무사히 되었습니다. 하지만 그냥 만족할만큼 되면 개발이 아니지요. Modal 컴포넌트 창안에 모달창을 여는 핸들러를 선언해서 버튼을 누를때마다 true에서 false로 false에서 true로 바뀌게는 했지만

  1. 모달창을 열었을때 x자라고 쳐진 부분만 클릭했을때 되야했지만, 전체부분이 클릭대상이 되었습니다.
<ModalContainer >
        <ModalBtn onClick = {openModalHandler} > 
          {isOpen ? 'Opened!' : 'Open Modal'}
          {isOpen && <ModalBackdrop>
              <ModalView>
                <ModalViewButton onClick = {openModalHandler}>
                  X
                </ModalViewButton>
                "Hello states"
              </ModalView>
            </ModalBackdrop>}
        </ModalBtn>
      </ModalContainer>

기존에 밑으로 줄줄이 달아놓으니, 문제가 생겼던 거 같습니다.
그래서 버튼을 끝내고 별개의 것으로 취급하니 해결되었습니다.
찾아보니 '이벤트 버블링'으로 인한 문제 였습니다. 한 요소에 이벤트가 발생하면 그 부모의 이벤트도 발생한 다는 것입니다.
이럴경우 저처럼 분리시키던지 이벤트가 발생한 부분에 {e => e.openModalHandler}로 바꾸면 이러한 문제를 막을 수 있습니다.

<ModalContainer >
        <ModalBtn onClick = {openModalHandler} > 
          {isOpen ? 'Opened!' : 'Open Modal'}
        </ModalBtn>
          {isOpen && <ModalBackdrop>
              <ModalView>
                <ModalViewButton onClick = {openModalHandler}>
                  X
                </ModalViewButton>
                "Hello states"
              </ModalView>
            </ModalBackdrop>}
      </ModalContainer>
  1. css에 대한 이해의 부족으로 모달창의 영역이 관리가 되지않았습니다.

padding과 border의 중요성을 세삼 알게되었습니다.

  • ModalContainer 스타일 컴포넌트
const ModalContainer = styled.div`
  text-align: center; //가운데 정렬
  margin: 125px
  // 125px 만큼 여분
  // auto;auto : 가로 중앙에 배치한다는 뜻, 그리고 자연스럽게 좌우 여백은 균등하게 배분
  width: 100%; //영역을 다루는게 아직 미숙하다...
  height: 5rem;
`;
  • ModalBackdrp 스타일 컴포넌트
  const ModalBackdrop = styled.div`
 // TODO : Modal이 떴을 때의 배경을 깔아주는 CSS를 구현합니다.
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  position: fixed;
  //position : absolute 원래 위치와 상관없이 위치를 지정, 가장 가까운 상위 요소를 기준으로 위치가 결정
  //position : fixed 원래 위치와 상관없이 위치를 지정, 상위요소에 영향받지않기 떄문에 화면이 바뀌더라도 고정된 위치를 설정할 수 있다
  background-color: rgba(0, 0, 0, 0.6);
`;
  • ModalView 스타일 컴포넌트
  const ModalView = styled.div.attrs(props => ({
  role: 'dialog'
}))`
  width: 300px;
  height: 300px;
  border-radius: 10px; // 모서리 깍기
  background-color: white;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%); // 가운데 정렬하는 또 다른 방법
  font-size: 2em;
  color: black
  `;

출처

http://www.gnujava.com/board/article_view.jsp?article_no=3797&board_no=11&table_cd=EPAR04&table_no=04

https://dkmqflx.github.io/frontend/2021/04/26/react-modal-close/

profile
읽고 기록하고 고민하고 사용하고 개발하자!

0개의 댓글