귀여운 눈높이에서 작성된, 🐰

하루 한 걸음씩, 성장 하는 중 입니다 🫶🏻

Studying/React

리액트 공부하기 - 모달 만들기

creamymood 2025. 6. 28. 12:05

모달에 대한 뭔가 알수없는 공포(?)가 있었다 ㅋㅋ

이번에 쉬운 예제로써 한번 경험해보고 어렵지 않다는걸 알았다

초보분들도 이해할 수 있게 참고할 수 있게 정리해보기


우선, 예제 연습 시작 전에 간단히 개념을 짚고 

모달에서 어떤것이 중요한지 알고 넘어가기 🐰


1. 모달이란? (원리부터 이해하기)

모달은 화면 위에 덮어씌우는 작은 창! 

  • 보통 배경은 어둡게 흐리게(반투명) 만들고,
  • 중앙에 내용이 팝업처럼 뜨지.

사용자가 모달 안의 작업을 하거나 확인을 하면 모달이 닫혀.
그래서 모달이 뜨고 안 뜨는 상태를 관리하는 게 중요해.

2. 모달 동작 원리

  • 모달을 보여줄지 말지를 결정하는 상태(state) 가 필요해.
  • 상태가 true면 모달 보이고, false면 모달 숨김.
  • 버튼 같은 걸 누르면 상태가 바뀌면서 모달이 열리고 닫히는 것!

3. 리액트에서 모달 만들기 (기본 구조)

import React, { useState } from "react";

export default function App() {
  // 모달 열림 여부 상태
  const [isModalOpen, setIsModalOpen] = useState(false);

  // 모달 열기 함수
  const openModal = () => setIsModalOpen(true);

  // 모달 닫기 함수
  const closeModal = () => setIsModalOpen(false);

  return (
    <div>
      <button onClick={openModal}>모달 열기</button>

      {/* 모달 상태가 true일 때만 모달 보여주기 */}
      {isModalOpen && (
        <div className="modal-backdrop" onClick={closeModal}>
          {/* onClick은 배경 클릭 시 모달 닫기 */}

          <div className="modal-content" onClick={e => e.stopPropagation()}>
            {/* 모달 안 내용 - 클릭해도 닫히지 않게 막기 */}
            <h2>모달 제목</h2>
            <p>여기에 모달 내용이 들어갑니다.</p>
            <button onClick={closeModal}>닫기</button>
          </div>
        </div>
      )}
    </div>
  );
}

 

4. 모달 디자인 어디서 하나?

  • 위 코드의 .modal-backdrop 과 .modal-content 를 CSS로 꾸미면 돼!
  • 보통 이렇게 스타일 줘:
.modal-backdrop {
  position: fixed; /* 화면 고정 */
  top: 0; left: 0; right: 0; bottom: 0;
  background-color: rgba(0,0,0,0.5); /* 검은색 반투명 배경 */
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 999; /* 가장 위에 오도록 */
}

.modal-content {
  background: white;
  padding: 20px;
  border-radius: 8px;
  min-width: 300px;
}

 

5. 정리

  • 모달이란? 화면 위에 띄우는 작은 팝업창.
  • 모달의 열림/닫힘 상태를 useState로 관리한다.
  • 모달이 열려 있으면 배경과 내용 컴포넌트를 화면에 렌더링한다.
  • 배경 클릭하거나 닫기 버튼 누르면 상태를 바꿔 모달 닫는다.
  • 디자인은 CSS로 배경 반투명, 내용은 흰색 박스 등 꾸민다.

6. 타입스크립트 적용 팁

  • 컴포넌트 props에 타입 지정하기
  • 예를 들어, 모달 컴포넌트를 따로 만들면:
type ModalProps = {
  onClose: () => void;
  children: React.ReactNode;
};

export function Modal({ onClose, children }: ModalProps) {
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal-content" onClick={e => e.stopPropagation()}>
        {children}
        <button onClick={onClose}>닫기</button>
      </div>
    </div>
  );
}

이렇게 하면 재사용성도 좋아!


우선 이렇게, 모달을 만들 때는 상태가 필수인걸로 알게 됐다.♥︎

 

이제, 실제로 연습해볼 예제 목표는

💡 예제 목표

✓버튼 클릭 → 모달 열림
✓모달 안에 간단한 메시지랑 닫기 버튼

 

 

그러면 예제 구현 목표에 맞게 ..! 코드를 작성해보자

해당 연습 예제는, 모달 컴포넌트를 따로 분리한 것 


우선 전체 코드는 다음과 같다.

import React, { useState } from "react";

function SimpleModal({ onClose }) {
  return (
    <div 
      style={{
        position: "fixed",
        top: 0, left: 0, right: 0, bottom: 0,
        backgroundColor: "rgba(0,0,0,0.3)",
        display: "flex", justifyContent: "center", alignItems: "center",
      }}
    >
      <div style={{ backgroundColor: "white", padding: 30, borderRadius: 10 }}>
        <h2>안녕하세요! 👋</h2>
        <p>이건 연습용 모달입니다.</p>
        <button onClick={onClose}>닫기</button>
      </div>
    </div>
  );
}

export default function App() {
  const [isModalOpen, setIsModalOpen] = useState(false);

  return (
    <div>
      <h1>모달 연습 페이지</h1>
      <button onClick={() => setIsModalOpen(true)}>모달 열기</button>

      {isModalOpen && <SimpleModal onClose={() => setIsModalOpen(false)} />}
    </div>
  );
}

모달에서는 상태가 필수 ⭐️

상태로써, 모달을 열고 닫는게 필요하기 때문이다.

 

function SimpleModal({ onClose }) {
  return (
    <div 
      style={{
        position: "fixed",
        top: 0, left: 0, right: 0, bottom: 0,
        backgroundColor: "rgba(0,0,0,0.3)",
        display: "flex", justifyContent: "center", alignItems: "center",
      }}
    >
      <div style={{ backgroundColor: "white", padding: 30, borderRadius: 10 }}>
        <h2>안녕하세요! 👋</h2>
        <p>이건 연습용 모달입니다.</p>
        <button onClick={onClose}>닫기</button>
      </div>
    </div>
  );
}

해당 코드를 설명해보자면,

 ✏️ SimpleModal이라는 모달 컴포넌트를 만들었다.

→ 이 컴포넌트는 자식 컴포넌트로써 App. 부모 컴포넌트에서 사용 된다.

 

 

난 항상 Props 때문에 이 부모 > 자식 흐름이 어려운데, 

여기서도 SimpleModal이 코드 작성 된 흐름 상, 위에 있기 때문에

뭔가 또 느낌이  이 컴포넌트가 부모인 느낌이라, 프롭스를 내려주는게 종종 헷갈린다.

 

아무튼, 이렇게 재사용될 SimpleModal 컴포넌트를 먼저 미리 만들어줬다.

 

여기서, 버튼의 OnClick, onClose 이 부분이 조금 헷갈릴테지만 잠시만 넘어가보고 app부터 보자! 

 

export default function App() {
  const [isModalOpen, setIsModalOpen] = useState(false);

  return (
    <div>
      <h1>모달 연습 페이지</h1>
      <button onClick={() => setIsModalOpen(true)}>모달 열기</button>

      {isModalOpen && <SimpleModal onClose={() => setIsModalOpen(false)} />}
    </div>
  );
}

 

✏️ 버튼을 눌러, 모달을 키고, 끄기 위해서 상태를 먼저 만들어줬다.

isModalOpen이 true일 경우, 모달이 보이게. false일 경우 꺼지게.

초기값은 꺼진 상태로써 false를 준 것!

 

<button onClick={() => setIsModalOpen(true)}>모달 열기</button>

 

버튼을 누르면, onClick 함수가 실행된다.

이 함수는 setIsModalOpen함수를 true로 바꿔준다. 

 

그 때, 이 isModalOpen이 true가 되고, 

true가 됐을 때. <SimpleModal> 컴포넌트가 등장하는 것!

{isModalOpen && <SimpleModal onClose={() => setIsModalOpen(false)} />}

..

..

 

이까진 이해가 쉬운데, 여기서 onClose 부분은 뭘까 ! ?

 

이 부분은, 

onClose 라는 함수를 내려주는 것. 자식에게!

이 onClose 함수는.. 상태를 false로 바꿔주는 거다.

 

더보기

 onClose는 어떤 역할?

 모달을 닫는 함수

  • 모달을 닫으려면 setIsModalOpen(false)를 실행해야 하는데
  • 근데 모달 컴포넌트 안에서는 직접적으로 setIsModalOpen에 접근할 수 없다.
  • 그래서 부모 컴포넌트(App) 가 만든 setIsModalOpen(false)를 함수로 만들어서 props로 내려준다.

자식 컴포넌트(SimpleModal)

function SimpleModal({ onClose }) {
  ...
  <button onClick={onClose}>닫기</button>
  ...
}
  • 모달 내부에서 "닫기" 버튼 클릭 → onClose() 실행
  • 결과적으로 setIsModalOpen(false)가 실행 → 모달이 닫힘

 

 

그래서 다시 모달 컴포넌트로 넘어가면,

 

부모app에서 넘겨받은 onClose함수를 내려받아서,

function SimpleModal({ onClose }) {
  return (
    <div 
      style={{
        position: "fixed",
        top: 0, left: 0, right: 0, bottom: 0,
        backgroundColor: "rgba(0,0,0,0.3)",
        display: "flex", justifyContent: "center", alignItems: "center",
      }}
    >
      <div style={{ backgroundColor: "white", padding: 30, borderRadius: 10 }}>
        <h2>안녕하세요! 👋</h2>
        <p>이건 연습용 모달입니다.</p>
        <button onClick={onClose}>닫기</button> //여기!!! 
      </div>
    </div>
  );
}

상태를 false로 바꾸는 함수를 여기서 사용할 수 있는 것 ! 

 


기능적인 부분은 이렇다.

디자인 적 요소를 살펴본다면

function SimpleModal({ onClose }) {
  return (
    <div 
      style={{
        position: "fixed",
        top: 0, left: 0, right: 0, bottom: 0,
        backgroundColor: "rgba(0,0,0,0.3)",
        display: "flex", justifyContent: "center", alignItems: "center",
      }}
    >

여기서 이 div가 모달 배경이 되는거다.

 

그러니까, 상태가 true로 바뀌어서 모달 보여줘! 하면

function SimpleModal({ onClose }) {
  return (
    <div 
      style={{
        position: "fixed",
        top: 0, left: 0, right: 0, bottom: 0,
        backgroundColor: "rgba(0,0,0,0.3)",
        display: "flex", justifyContent: "center", alignItems: "center",
      }}
    >
      <div style={{ backgroundColor: "white", padding: 30, borderRadius: 10 }}>
        <h2>안녕하세요! 👋</h2>
        <p>이건 연습용 모달입니다.</p>
        <button onClick={onClose}>닫기</button>
      </div>
    </div>
  );
}

이 모달 컴포넌트가 짜란~ 하고 나타나는건데

 

배경은 저렇게 div로 살짝 불투명한거고,

그 위에 이제 모달이 안녕~ 하고 나타나는 것!🐰🤍

 

정말 어렵지 않게 구현할 수 있었다. 

쉬운 예제부터 하나씩 쳐보는게 중요한 것 같다.