모달 창 만들기

Donggu(oo)·2023년 1월 22일
0

React 기능 구현

목록 보기
4/14
post-thumbnail

1. 알아야 할 내용

  • 아래 코드는 모달 창의 'X' 버튼이 아닌 여백 아무 곳이나 클릭해도 창이 사라지는 것(이벤트 버블링)을 막기 위해 필요하다.
const stopEvent = (event) => { event.stopPropagation() };
  • 모달이 띄워졌을 때 뒷 배경의 스크롤을 막기 위해 기존 이벤트 핸들러 1개로 동작하는 구조에서 모달을 띄우는 이벤트 핸들러, 닫는 이벤트 핸들러 2개로 나눈 후 띄우는 이벤트 핸들러에는 body의 스크롤을 막고, 닫는 이벤트 핸들러에는 body의 스크롤을 다시 동작하는 코드를 추가한다.
  • 기존 모달 on/off 이벤트 핸들러 상태에서는 모달이 열려도 뒷 배경에 스크롤이 동작하는 것을 볼 수 있다.
// 기존 모달 on/off 이벤트 핸들러
const openModalHandler = () => {
  setIsOpen(!isOpen)
};

// 모달을 띄울 때와 닫을 때 둘 다 같은 이벤트 핸들러를 사용한다.
<button onClick={openModalHandler}>Open</button>
<div className='closebtn' onClick={openModalHandler}>X</div>

  • 뒷 배경의 스크롤을 막기 위해 2개로 나눈 모달 on/off 이벤트 핸들러 상태에서는 뒷 배경 스크롤이 동작하지 않는 것을 볼 수 있다.
// 뒷 배경의 스크롤을 막기 위해 2개로 나눈 모달 on/off 이벤트 핸들러
const openModalHandler = () => {
  setIsOpen(!isOpen);
  document.body.style.cssText = `
  position: fixed; 
  top: -${window.scrollY}px;
  overflow-y: scroll;
  width: 100%;`;
};

const closeModalHandler = () => {
  setIsOpen(!isOpen);
  const scrollY = document.body.style.top;
  document.body.style.cssText = '';
  window.scrollTo(0, parseInt(scrollY || '0', 10) * -1);
};

// 모달을 띄울 때와 닫을 때 각각의 이벤트 핸들러를 사용한다.
<button onClick={openModalHandler}>Open</button>
<div className='closebtn' onClick={closeModalHandler}>X</div>

2. 전체 코드


  • 모달 창 구현 코드
import { useState } from 'react';
import styled from 'styled-components';

// 모달 뒷배경
const ModalBackdrop = styled.div`
  position: fixed;
  z-index: 999;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background-color: rgba(0,0,0,0.4);
  display: grid;
  place-items: center;
`;

// 모달 창
const ModalView = styled.div`
  border-radius: 5px;
  background-color: white;
  width: 700px;
  height: 430px;
  box-shadow: 0 0 20px rgba(0, 0, 0, 0.19), 0 10px 10px rgba(0, 0, 0, 0.1);

  > .closebtn {
    text-align: center;
    margin-bottom: 50px;
    font-size: 30px;
    &:hover {
      color: gray;
    }
  }

  > .content {
    text-align: center;
    font-size: 50px;
  }
`;

export const Modal = () => {
  const [isOpen, setIsOpen] = useState(false);

  // 모달 open 이벤트 핸들러
  const openModalHandler = () => {
    setIsOpen(!isOpen);
    document.body.style.cssText = `
    position: fixed; 
    top: -${window.scrollY}px;
    overflow-y: scroll;
    width: 100%;`;
  };

  // 모달 close 이벤트 핸들러
  const closeModalHandler = () => {
    setIsOpen(!isOpen);
    const scrollY = document.body.style.top;
    document.body.style.cssText = '';
    window.scrollTo(0, parseInt(scrollY || '0', 10) * -1);
  };

  // 이벤트 버블링 방지
  const stopEvent = (event) => { event.stopPropagation() };

  return (
    <>
      <button onClick={openModalHandler}>Open</button>
      {isOpen ?
        <ModalBackdrop onClick={openModalHandler}>
          <ModalView onClick={stopEvent}>
            <div className='closebtn' onClick={closeModalHandler}>X</div>
            <div className='content'>Modal content</div>
          </ModalView>
        </ModalBackdrop> : null}
    </>
  );
};

0개의 댓글