(1) 반복은 개발자의 적!
function App() {
return (
<div>
<div className="user-card">
<img src="/user1.jpg" alt="사용자1" />
<h3>홍길동</h3>
<p>개발자</p>
</div>
<div className="user-card">
<img src="/user2.jpg" alt="사용자2" />
<h3>김철수</h3>
<p>디자이너</p>
</div>
<div className="user-card">
<img src="/user3.jpg" alt="사용자3" />
<h3>이영희</h3>
<p>기획자</p>
</div>
</div>
);
}
이 코드의 문제점
- 반복 지옥 : 같은 구조를 3번 복붙
- 수정 지옥 : 디자인 바뀌면 3곳 다 고쳐야 함
- 사용자 10,000명이면? 답이 없
(2) 컴포넌트로 추출하기 - Before / After
❌ Before: 반복되는 코드
<div className="user-card">
<img src="/user1.jpg" alt="사용자1" />
<h3>홍길동</h3>
<p>개발자</p>
</div>
✅ After: 재사용 가능한 컴포넌트
// 틀 하나 만들고
function UserCard({ image, name, job }) {
return (
<div className="user-card">
<img src={image} alt={name} />
<h3>{name}</h3>
<p>{job}</p>
</div>
);
}
// 마음껏 찍어내기
function App() {
return (
<div>
<UserCard image="/user1.jpg" name="홍길동" job="개발자" />
<UserCard image="/user2.jpg" name="김철수" job="디자이너" />
<UserCard image="/user3.jpg" name="이영희" job="기획자" />
</div>
);
}
(3) 배열 데이터로 자동 렌더링
실무에선 데이터가 배열로 들어옴. 이럴 땐 map과 찰떡궁합임
function UserList() {
const users = [
{ id: 1, image: '/user1.jpg', name: '홍길동', job: '개발자' },
{ id: 2, image: '/user2.jpg', name: '김철수', job: '디자이너' },
{ id: 3, image: '/user3,jpg', name: '이영희', job: '기획자' }
];
return (
<div>
{users.map(user => (
<UserCard
key={user.id}
image={user.image}
name={user.name}
job={user.job}
/>
))}
</div>
);
}
(4) 범용 Button 컴포넌트 - 실전 설계
function Button({
children, // 버튼 안에 들어갈 내용
onClick, // 클릭 이벤트
variant = 'primary', // 색상 테마 (기본값)
size = 'medium', // 크기 (기본값)
disabled = false // 비활성화 여부
}) {
return (
<button
className={`btn btn-${variant} btn-${size}`}
onClick={onClick}
disabled={disabled}
>
{children}
</button>
);
}
다양하게 활용
<Button>기본 버튼</Button>
<Button variant="secondary">보조 버튼</Button>
<Button variant="danger" size="large">삭제</Button>
<Button disabled>비활성화</Button>
<Button onClick={handleSave}>저장</Button>
같은 Button 컴포넌트 하나로 수십 가지 스타일을 만들 수 있음
설계 포인트
| 요소 | 역할 |
| children | 내용은 자유롭게(이모지, 아이콘 조합 가능) |
| variant, size | 정해진 선택지 중 고르기 |
| 기본값 (= 'primary') | 안 넘겨도 동작하게 |
| disabled | 불린 props(있으면 true) |
(5) 좋은 재사용 컴포넌트의 3가지 조건
1. 단일 책임 - 한 가지 역할만
// ❌ 너무 많은 일을 함
function UserCardWithSearchAndFilter() { ... }
// ✅ 하나의 역할에 집중
function UserCard() { ... } // 카드 표시만
function SearchBar() { ... } // 검색만
function FilterPanel() { ... } // 필터만
2. 적절한 추상화 - 유연하지만 복잡하지 않게
// ❌ 너무 경직됨 - 재사용 불가
function BlueLargeBoldButton() {
return <button style={{ color: 'blue', fontSize: 20, fontWeight: 'bold' }}>저장</button>;
}
// ❌ 너무 유연함 - Props 지옥
function Button({
color, fontSize, fontWeight, padding, margin, border, borderRadius, shadow, hoverColor, ...
}) { ... }
// ✅ 적당히 유연함
function Button({ children, variant, size, onClick }) { ... }
3. Props로 커스터마이즈 - 외부에서 조정 가능
// ❌ 하드코딩
function Greeting() {
return <h1>안녕하세요, 홍길동님!</h1>; // 이름 고정
}
// ✅ 외부에서 주입
function Greeting({ name }) {
return <h1>안녕하세요, {name}님!</h1>;
}
(6) 자주 하는 안티패턴
❌ 안티패턴 1: 너무 이른 추출 (Premature Abstraction)
// ❌ 딱 한 곳에서만 쓰는데 굳이 컴포넌트화
function OnlyUsedOnceHeader() {
return <h1 className="special">특별 제목</h1>;
}
문제점: 재사용 없이 그냥 파일만 늘어남. 2번 이상 반복될 때 추출하기
❌ 안티패턴 2: 너무 많은 Props (Props 지옥)
// ❌ 이 컴포넌트를 쓸 때마다 공포...
<Card
title="제목"
subtitle="부제"
content="내용"
footer="푸터"
iconName="star"
iconColor="gold"
hasShadow={true}
shadowLevel={3}
borderColor="blue"
borderWidth={2}
padding={16}
margin={8}
...
/>
해결: 관련 props는 객체로 묶거나, children을 적극 활용하기
<Card> <CardHeader>제목</CardHeader> <CardBody>내용</CardBody> <CardFooter>푸터</CardFooter> </Card>
❌ 안티패턴 3: 조건문 범벅 컴포넌트
// ❌ 두 완전히 다른 UI를 하나에 섞기
function UserOrAdminCard({ isAdmin, user }) {
if (isAdmin) {
return <div>...관리자 전용 UI 100줄...</div>;
} else {
return <div>...일반 유저 UI 100줄...</div>;
}
}
문제점: 2개의 다른 컴포넌트를 억지로 합친 상태
// ✅ 두 개로 분리 function AdminCard({ user }) { ... } function UserCard({ user }) { ... }
❌ 안티패턴 4: 범용이라는 이름의 신의 컴포넌트
// ❌ "만능 컴포넌트"를 만들려는 시도
function SuperButton({ type, variant, icon, loading, tooltip, dropdown, ... }) {
// 500줄 코드...
}
해결: 합성(Composition) 활용
<Button> <Icon name="save" /> 저장 </Button>
'DEV > React' 카테고리의 다른 글
| React로 데이터 다루기 - 1-1. 배열과 데이터 렌더링 (0) | 2026.08.25 |
|---|---|
| [React 개발 기초] 10. React가 렌더링하는 방식 (0) | 2026.08.10 |
| [React 개발 기초] 8. 참조형 State (0) | 2026.08.10 |
| [React 개발 기초] 7. State (1) | 2026.08.10 |
| [React 개발 기초] 6. children (0) | 2026.08.10 |