🧩
EPISODE 01
단일 책임 · children · render prop · 합성 vs 상속
컴포넌트 심화
컴포넌트 설계의 핵심 원칙(단일 책임), children/render prop 패턴, 조건부 렌더링 3가지 방법, 그리고 React가 권장하는 합성 vs 상속을 다룹니다.
React컴포넌트합성
소요 시간
⏱ 45~60분
난이도
📊 중급
선수 조건
🎯 ts-06
결과물
역할이 분리되고 합성 가능한 컴포넌트 설계
이 강의에서 배우는 것
- 1컴포넌트는 한 가지 역할만 한다는 단일 책임을 적용한다
- 2children과 render prop으로 유연한 컴포넌트를 만든다
- 3&&, 삼항, 컴포넌트 분리 — 조건부 렌더링 3가지를 구분한다
- 4상속 대신 합성으로 컴포넌트를 확장한다
1. 단일 책임 원칙
jsx
// ❌ 나쁜 예 — 하나의 컴포넌트가 너무 많은 일
function UserCard() {
const [user, setUser] = useState(null);
useEffect(() => {
fetch('/api/user').then(r => r.json()).then(setUser);
}, []);
return (
<div>
<img src={user?.avatar} />
<h2>{user?.name}</h2>
<button onClick={() => alert('팔로우!')}>팔로우</button>
</div>
);
}
// ✅ 좋은 예 — 역할 분리
function UserAvatar({ src, alt }) { return <img src={src} alt={alt} />; }
function FollowButton({ onFollow }) { return <button onClick={onFollow}>팔로우</button>; }
function UserCard({ user, onFollow }) {
return (
<div>
<UserAvatar src={user.avatar} alt={user.name} />
<h2>{user.name}</h2>
<FollowButton onFollow={onFollow} />
</div>
);
}2. children props
jsx
function Card({ children }) {
return (
<div style={{ border: '1px solid #ddd', padding: 16, borderRadius: 8 }}>
{children}
</div>
);
}
<Card>
<h2>제목</h2>
<p>내용이 여기에 들어갑니다.</p>
</Card>레이아웃·래퍼 컴포넌트에 자주 사용.
3. render prop 패턴
jsx
function DataFetcher({ url, render }) {
const [data, setData] = useState(null);
useEffect(() => {
fetch(url).then(r => r.json()).then(setData);
}, [url]);
return render(data);
}
<DataFetcher url="/api/users" render={(users) => (
<ul>{users?.map(u => <li key={u.id}>{u.name}</li>)}</ul>
)} />4. 조건부 렌더링
&& 연산자 (단순)
jsx
{hasMessage && <p>{message}</p>}
// 주의: hasMessage가 0이면 "0"이 출력됨 → Boolean(hasMessage) 권장삼항 (둘 중 하나)
jsx
{isLoggedIn ? <button>로그아웃</button> : <button>로그인</button>}컴포넌트 분리 (복잡)
jsx
function UserProfile({ isLoading, error, user }) {
if (isLoading) return <LoadingSpinner />;
if (error) return <ErrorMessage message={error} />;
return <div>{user.name}</div>;
}5. 합성 vs 상속
| 구분 | 합성 | 상속 |
|---|---|---|
| 방법 | children, props로 조합 | class extends |
| 유연성 | 높음 | 낮음 |
| React 권장 | ✅ | ❌ |
jsx
function Dialog({ title, message, children }) {
return (
<div className="dialog">
<h1>{title}</h1>
<p>{message}</p>
{children}
</div>
);
}
function WelcomeDialog() {
return (
<Dialog title="환영합니다!" message="React 심화 과정에 오신 것을 환영합니다.">
<button>시작하기</button>
</Dialog>
);
}