Skip to content

Modal 컴포넌트 사용 가이드

pillow12360 edited this page Nov 25, 2024 · 1 revision

Modal 컴포넌트 사용 가이드

목차

  1. 소개
  2. 기본 사용법
  3. 서브 컴포넌트
  4. Props
  5. 예제
  6. Best Practices

1. 소개

Modal 컴포넌트는 합성 컴포넌트 패턴을 사용하여 구현된 재사용 가능한 다이얼로그 컴포넌트입니다.

특징

  • 직관적인 API
  • 유연한 커스터마이징
  • 접근성 지원
  • TypeScript 지원

Import 방법

import { Modal, useModal } from '@/components/Modal';

2. 기본 사용법

기본 구조

function Example() {
  const [isOpen, setIsOpen] = useState(false);
  
  return (
    <>
      <Button onClick={() => setIsOpen(true)}>모달 열기</Button>
      
      <Modal isOpen={isOpen} onClose={() => setIsOpen(false)}>
        <Modal.Header>
          <h2>제목</h2>
          <Modal.CloseButton onClick={() => setIsOpen(false)} />
        </Modal.Header>
        <Modal.Content>
          <p>내용</p>
        </Modal.Content>
        <Modal.Footer>
          <Button onClick={() => setIsOpen(false)}>닫기</Button>
        </Modal.Footer>
      </Modal>
    </>
  );
}

Context를 사용한 전역 상태 관리

// App.tsx에 Provider 추가
function App() {
  return (
    <Modal.Provider>
      <AppContent />
    </Modal.Provider>
  );
}

// 컴포넌트에서 useModal 훅 사용
function Example() {
  const { openModal, closeModal } = useModal();
  
  const handleOpenModal = () => {
    openModal(
      <Modal.Content>
        <p>모달 내용</p>
      </Modal.Content>
    );
  };
  
  return <Button onClick={handleOpenModal}>모달 열기</Button>;
}

3. 서브 컴포넌트

Modal.Header

헤더 영역을 정의하는 컴포넌트

<Modal.Header>
  <h2>제목</h2>
  <Modal.CloseButton />
</Modal.Header>

Modal.Content

본문 영역을 정의하는 컴포넌트

<Modal.Content>
  <p>모달의 내용이 들어갑니다.</p>
</Modal.Content>

Modal.Footer

하단 영역을 정의하는 컴포넌트

<Modal.Footer>
  <Button variant="ghost">취소</Button>
  <Button variant="primary">확인</Button>
</Modal.Footer>

Modal.CloseButton

닫기 버튼 컴포넌트

<Modal.CloseButton onClick={onClose} />

4. Props

Modal (ModalRoot)

Prop Type Required Description
isOpen boolean Yes 모달의 표시 여부
onClose () => void Yes 모달 닫기 핸들러
className string No 추가 스타일 클래스

서브 컴포넌트 공통

Prop Type Required Description
children ReactNode No 컴포넌트 내용
className string No 추가 스타일 클래스

5. 예제

기본적인 알림 모달

function AlertModal() {
  const [isOpen, setIsOpen] = useState(false);
  
  return (
    <Modal isOpen={isOpen} onClose={() => setIsOpen(false)}>
      <Modal.Header>
        <h2>알림</h2>
      </Modal.Header>
      <Modal.Content>
        <p>처리가 완료되었습니다.</p>
      </Modal.Content>
      <Modal.Footer>
        <Button onClick={() => setIsOpen(false)}>확인</Button>
      </Modal.Footer>
    </Modal>
  );
}

확인 모달

function ConfirmModal({ isOpen, onClose, onConfirm, message }) {
  return (
    <Modal isOpen={isOpen} onClose={onClose}>
      <Modal.Header>
        <h2>확인</h2>
        <Modal.CloseButton onClick={onClose} />
      </Modal.Header>
      <Modal.Content>
        <p>{message}</p>
      </Modal.Content>
      <Modal.Footer>
        <Button variant="ghost" onClick={onClose}>취소</Button>
        <Button variant="primary" onClick={onConfirm}>확인</Button>
      </Modal.Footer>
    </Modal>
  );
}

커스텀 스타일링

<Modal 
  isOpen={isOpen} 
  onClose={onClose}
  className="max-w-2xl"
>
  <Modal.Header className="bg-primary text-white">
    <h2>커스텀 스타일 모달</h2>
  </Modal.Header>
  <Modal.Content className="py-8">
    <p>내용</p>
  </Modal.Content>
</Modal>

6. Best Practices

1. 모달 상태 관리

// ❌ 잘못된 예시
<Modal isOpen={true}>

// ✅ 좋은 예시
const [isOpen, setIsOpen] = useState(false);
<Modal isOpen={isOpen} onClose={() => setIsOpen(false)}>

2. 접근성 고려

// ✅ 제목에 적절한 헤딩 태그 사용
<Modal.Header>
  <h2>모달 제목</h2>
</Modal.Header>

// ✅ 닫기 버튼에 적절한 레이블 제공
<Modal.CloseButton aria-label="모달 닫기" />

3. 조건부 렌더링

// ✅ 조건부로 푸터 표시
<Modal>
  <Modal.Header>제목</Modal.Header>
  <Modal.Content>내용</Modal.Content>
  {showFooter && (
    <Modal.Footer>
      <Button>확인</Button>
    </Modal.Footer>
  )}
</Modal>

4. 에러 처리

try {
  await handleSubmit();
  closeModal();
} catch (error) {
  // 에러 처리
  openModal(
    <Modal.Content>
      <p>처리  오류가 발생했습니다.</p>
    </Modal.Content>
  );
}