Ch.25 컴포넌트 설계 — 재사용 가능한 UI
합성 패턴 — children과 슬롯
children prop으로 래퍼 컴포넌트를 만들 수 있다슬롯 패턴으로 유연한 레이아웃 컴포넌트를 설계할 수 있다Modal, Card, Layout 컴포넌트를 합성 패턴으로 구현할 수 있다
카드 안에 들어갈 내용이 매번 다르다면?
카드 컴포넌트를 만들었는데 어떤 곳에서는 이미지가, 어떤 곳에서는 텍스트만, 또 어떤 곳에서는 버튼이 들어갑니다.
내용물이 달라질 때마다 새 컴포넌트를 만들어야 할까?
합성(Composition) 패턴을 쓰면, 틀은 고정하고 내용만 자유롭게 바꿀 수 있습니다.
article
핵심 내용
children은 컴포넌트 안에 무엇이든 넣을 수 있는 구멍입니다
// 래퍼 컴포넌트 — 테두리만 제공
function Card({ children }: { children: React.ReactNode }) {
return (
<div className="rounded-lg border p-4 shadow-sm">
{children}
</div>
);
}
// 사용: 안에 무엇이든 넣을 수 있다
<Card>
<h2>제목</h2>
<p>설명 텍스트</p>
</Card>
<Card>
<img src="/photo.jpg" alt="사진" />
<button>좋아요</button>
</Card>// Layout 컴포넌트 — 페이지 공통 구조
function PageLayout({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen">
<Header />
<main className="max-w-4xl mx-auto p-4">
{children}
</main>
<Footer />
</div>
);
}
// 모든 페이지에서 재사용
<PageLayout>
<HomePage />
</PageLayout>핵심: children 패턴은 "구조는 고정, 내용은 자유"입니다. Card, Layout, Modal 등 틀을 제공하는 컴포넌트에 적합합니다.
children이 구멍 하나라면 슬롯은 구멍이 여러 개입니다
interface DialogProps {
header: React.ReactNode; // 슬롯 1: 상단
children: React.ReactNode; // 슬롯 2: 본문
footer?: React.ReactNode; // 슬롯 3: 하단 (선택)
}
function Dialog({ header, children, footer }: DialogProps) {
return (
<div className="rounded-xl border shadow-lg">
<div className="border-b p-4 font-bold">
{header}
</div>
<div className="p-4">
{children}
</div>
{footer && (
<div className="border-t p-4 flex justify-end gap-2">
{footer}
</div>
)}
</div>
);
}// 사용: 각 슬롯에 원하는 내용 배치
<Dialog
header={<h2>정말 삭제하시겠습니까?</h2>}
footer={
<>
<button>취소</button>
<button>삭제</button>
</>
}
>
<p>삭제된 데이터는 복구할 수 없습니다.</p>
</Dialog>합성 패턴으로 만드는 실전 컴포넌트 3가지
// 1. Modal — 오버레이 + 슬롯
function Modal({ isOpen, onClose, title, children }) {
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center">
<div className="bg-white rounded-xl p-6 max-w-md w-full">
<div className="flex justify-between mb-4">
<h2 className="text-lg font-bold">{title}</h2>
<button onClick={onClose}>✕</button>
</div>
{children}
</div>
</div>
);
}// 2. Card — 이미지 슬롯 + 본문
function Card({ image, children, actions }) {
return (
<div className="rounded-xl border overflow-hidden">
{image && <div className="aspect-video">{image}</div>}
<div className="p-4">{children}</div>
{actions && (
<div className="border-t p-3 flex gap-2">{actions}</div>
)}
</div>
);
}
// 사용
<Card
image={<img src="/thumb.jpg" alt="" />}
actions={<button>상세보기</button>}
>
<h3>프로젝트 제목</h3>
<p>설명...</p>
</Card>바이브 코더 팁 AI에게 "children과 슬롯 패턴을 사용하는 Modal 컴포넌트를 만들어줘"라고 하면 유연하고 재사용 가능한 결과를 받을 수 있습니다.
children prop의 역할은?
슬롯 패턴은 header, footer 같은 여러 영역을 Props로 받아 배치하는 방식이다.
다음 중 children 패턴이 가장 적합한 컴포넌트는?
compare_arrows
비교 정리
| 항목 | children만 | 슬롯 패턴 |
|---|---|---|
| 구멍 수 | 1개 (children) | 여러 개 (header, footer 등) |
| 적합한 경우 | 단순 래퍼 (Card, Container) | 영역이 나뉜 UI (Dialog, Page) |
edit_note
정리 노트
합성 패턴(Composition) 핵심 정리
children 패턴
- children
- 컴포넌트 태그 사이의 내용이 자동으로 children prop으로 전달
- 래퍼 컴포넌트
- Layout, Card 등 구조를 감싸고 내부 내용은 자유롭게 변경
슬롯 패턴
- named slots
- header, footer 등 이름이 있는 Props로 여러 위치에 내용 삽입
- 활용 사례
- Modal의 title/body/footer, Layout의 header/sidebar/content
★
children은 단일 슬롯, 여러 위치에 내용을 넣으려면 named slot Props를 사용하세요.
퀴즈와 인터랙션으로 더 깊이 학습하세요
play_circle인터랙티브 레슨 시작