[React] Modal Component ๊ตฌํ˜„ํ•˜๊ธฐ

fejiguยท2022๋…„ 8์›” 29์ผ
8

Toy Project

๋ชฉ๋ก ๋ณด๊ธฐ
1/6
post-thumbnail

๐Ÿ‘‰๐Ÿป Modal UI ์ปดํฌ๋„ŒํŠธ๋Š” ๊ธฐ์กด์˜ ๋ธŒ๋ผ์šฐ์ € ํŽ˜์ด์ง€ ์œ„์— ์ƒˆ๋กœ์šด ์œˆ๋„์šฐ ์ฐฝ์ด ์•„๋‹Œ, ๋ ˆ์ด์–ด๋ฅผ ๊นŒ๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค. ์ด๋ฒˆ์—๋Š” ์‹ค์ œ๋กœ Modal Component๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค. ๋‹ค์‹œ ์ •๋ฆฌํ•˜๋ฉฐ ์™„์ „ํžˆ ๋‚ด๊ฒƒ์œผ๋กœ ๋งŒ๋“ค๋ ค๊ณ  ํ•œ๋‹ค.


๐Ÿ’ป Modal ๊ตฌํ˜„ ๊ฒฐ๊ณผ

โœ”๏ธ OPEN Modal ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋ชจ๋‹ฌ์ฐฝ ๋œจ๊ฒŒ ํ•˜๊ธฐ
โœ”๏ธ ๋ชจ๋‹ฌ์ฐฝ์˜ X ๋ฒ„ํŠผ ๋ˆ„๋ฅด๋ฉด ์ฐฝ ๋‹ซ๊ธฐ
โœ”๏ธ ๋ชจ๋‹ฌ ํฐ์ƒ‰์ฐฝ์„ ๋ˆ„๋ฅด๋ฉด ์ฐฝ ๋‹ซํžˆ์ง€ ์•Š๊ฒŒ ํ•˜๊ธฐ
โœ”๏ธ ๋ชจ๋‹ฌ์ฐฝ ์™ธ ์•„๋ฌด๊ณณ์ด๋‚˜ ๋ˆ„๋ฅด๋ฉด ์ฐฝ ๋‹ซ๊ธฐ


โญ๏ธโญ๏ธโญ๏ธ ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ์ 

๐Ÿ”Ž z-index: 1; : ์œ„์น˜ ์ง€์ • ์š”์†Œ์™€, ๊ทธ ์ž์† ๋˜๋Š” ํ•˜์œ„ ํ”Œ๋ ‰์Šค ์•„์ดํ…œ์˜ Z์ถ• ์ˆœ์„œ๋ฅผ ์ง€์ •ํ•œ๋‹ค. ๋” ํฐ z-index ๊ฐ’์„ ๊ฐ€์ง„ ์š”์†Œ๊ฐ€ ์ž‘์€ ๊ฐ’์˜ ์š”์†Œ ์œ„๋ฅผ ๋ฎ๋Š”๋‹ค.

๐Ÿ”Ž > : ์ž์‹ ์š”์†Œ ํ‘œ๊ธฐ, ex) > div.desc {}

๐Ÿ”Ž onClick={(e) => e.stopPropagation()} : event ๋ฒ„๋ธ”๋ง(์ด๋ฒคํŠธ๊ฐ€ ์—ฐ์†ํ•˜์—ฌ ๋ฐœ์ƒํ•˜๋Š” ๋ฒ„๋ธ” ํ˜„์ƒ์„ ์˜๋ฏธ)์ด๋ฒคํŠธ๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ
โ†’ ๋ชจ๋‹ฌ์ฐฝ ์™ธ ๋ถ€๋ถ„์„ ๋ˆŒ๋ €์„๋•Œ๋งŒ, ์ฐฝ์ด ๋‹ซํ˜€์•ผํ•˜๋Š”๋ฐ ๋ชจ๋‹ฌ์ฐฝ์˜ ํฐ์ƒ‰์ฐฝ์„ ๋ˆŒ๋Ÿฌ๋„ ์ฐฝ์ด ๋‹ซํžˆ๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋Š”๋ฐ ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๐Ÿ”Ž setIsOpen(!isOpen) : !, ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๋ฉ”์†Œ๋“œ, ex) !false -> !true -> !false -> !true


๐Ÿ’ป Modal ์ฝ”๋“œ

import { useState } from 'react';
import styled from 'styled-components';

export const ModalContainer = styled.div`
  // Modal์„ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ์ „์ฒด์ ์œผ๋กœ ํ•„์š”ํ•œ CSS๋ฅผ ๊ตฌํ˜„
  display : flex;
  justify-content : center;
  align-items : center;
  height : 100%;
`;

export const ModalBackdrop = styled.div`
  // Modal์ด ๋–ด์„ ๋•Œ์˜ ๋ฐฐ๊ฒฝ์„ ๊น”์•„์ฃผ๋Š” CSS๋ฅผ ๊ตฌํ˜„
  z-index: 1; //์œ„์น˜์ง€์ • ์š”์†Œ
  position: fixed;
  display : flex;
  justify-content : center;
  align-items : center;
  background-color: rgba(0,0,0,0.4);
  border-radius: 10px;
  top : 0;
  left : 0;
  right : 0;
  bottom : 0;
`;

export const ModalBtn = styled.button`
  background-color: var(--coz-purple-600);
  text-decoration: none;
  border: none;
  padding: 20px;
  color: white;
  border-radius: 30px;
  cursor: grab;
`;

export const ExitBtn = styled(ModalBtn) `
background-color : #4000c7;
border-radius: 10px;
text-decoration: none;
margin: 10px;
padding: 5px 10px;
width: 40px;
height: 40px;
display : flex;
justify-content : center;
align-items : center;
`;

export const ModalView = styled.div.attrs((props) => ({
  // attrs ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด div ์—˜๋ฆฌ๋จผํŠธ์— ์†์„ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  role: 'dialog',
}))`
  // Modal์ฐฝ CSS๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  display: flex;
  align-items: center;
  flex-direction: column;
  border-radius: 20px;
  width: 500px;
  heigth: 200px;
  background-color: #ffffff;
    >div.desc {
      margin: 50px;
      font-size: 20px;
      color: var(--coz-purple-600);
    }
`;

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

  const openModalHandler = () => {
    // isOpen์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„
    // !false -> !true -> !false
    setIsOpen(!isOpen) 
  };

  return (
    <>
      <ModalContainer>
        <ModalBtn onClick={openModalHandler}
        // ํด๋ฆญํ•˜๋ฉด Modal์ด ์—ด๋ฆฐ ์ƒํƒœ(isOpen)๋ฅผ boolean ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 
        > Open Modal
          {/* ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ™œ์šฉํ•ด์„œ Modal์ด ์—ด๋ฆฐ ์ƒํƒœ(isOpen์ด true์ธ ์ƒํƒœ)์ผ ๋•Œ๋Š” ModalBtn์˜ ๋‚ด๋ถ€ ํ…์ŠคํŠธ๊ฐ€ 'Opened!' ๋กœ Modal์ด ๋‹ซํžŒ ์ƒํƒœ(isOpen์ด false์ธ ์ƒํƒœ)์ผ ๋•Œ๋Š” ModalBtn ์˜ ๋‚ด๋ถ€ ํ…์ŠคํŠธ๊ฐ€ 'Open Modal'์ด ๋˜๋„๋ก ๊ตฌํ˜„ */}
        </ModalBtn>
        {/* ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ํ™œ์šฉํ•ด์„œ Modal์ด ์—ด๋ฆฐ ์ƒํƒœ(isOpen์ด true์ธ ์ƒํƒœ)์ผ ๋•Œ๋งŒ ๋ชจ๋‹ฌ์ฐฝ๊ณผ ๋ฐฐ๊ฒฝ์ด ๋œฐ ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„ */}
        {isOpen ? 
        <ModalBackdrop onClick={openModalHandler}>
          //event ๋ฒ„๋ธ”๋ง์„ ๋ง‰๋Š” ๋ฉ”์†Œ๋“œ 
            <ModalView onClick={(e) => e.stopPropagation()}>
              <ExitBtn onClick={openModalHandler}>x</ExitBtn>
              <div className='desc'>HELLO FEJIGU!</div>
            </ModalView>
          </ModalBackdrop>
          : null
        }
      </ModalContainer>
    </>
  );
};
profile
์‹ ๊ทœ ์„œ๋น„์Šค์˜ ๊ธฐํš๋ถ€ํ„ฐ ๊ฐœ๋ฐœ, ์šด์˜๊นŒ์ง€ ์ „ ๊ณผ์ •์„ ๊ฒฝํ—˜ํ•œ ์ฃผ๋‹ˆ์–ด ๐Ÿ“ฑ

0๊ฐœ์˜ ๋Œ“๊ธ€