Props와 Children
2. Props와 Children
React에서 컴포넌트 간의 데이터 전달과 컴포넌트 조합을 위해 사용하는 Props와 Children의 고급 활용법을 배워보겠습니다.
2.1 Children Props란?
Children은 컴포넌트의 여는 태그와 닫는 태그 사이에 있는 모든 내용을 의미합니다. 이를 통해 더 유연하고 재사용 가능한 컴포넌트를 만들 수 있습니다.
2.1.1 기본 Children 사용법
function Container({ children }) {
return (
<div>
{children}
</div>
);
}
function App() {
return (
<div>
<Container>
<h2>제목</h2>
<p>이것은 컨테이너 안의 내용입니다.</p>
</Container>
<Container>
<ul>
<li>항목 1</li>
<li>항목 2</li>
<li>항목 3</li>
</ul>
</Container>
</div>
);
}
2.2 컴포넌트 조합 패턴
2.2.1 Layout 컴포넌트
function Header({ children }) {
return (
<header>
{children}
</header>
);
}
function Main({ children }) {
return (
<main>
{children}
</main>
);
}
function Footer({ children }) {
return (
<footer>
{children}
</footer>
);
}
function App() {
return (
<div>
<Header>
<h1>React 베이스캠프</h1>
<nav>
<a href="#home">홈</a> | <a href="#about">소개</a> | <a href="#contact">연락처</a>
</nav>
</Header>
<Main>
<h2>메인 컨텐츠</h2>
<p>여기에 주요 내용이 들어갑니다.</p>
<button>더 보기</button>
</Main>
<Footer>
<p>© 2025 React 베이스캠프. All rights reserved.</p>
</Footer>
</div>
);
}
2.2.2 Modal 컴포넌트
function Modal({ isOpen, onClose, title, children }) {
if (!isOpen) return null;
return (
<div>
<div>
<div>
<h3>{title}</h3>
<button
onClick={onClose}
>
×
</button>
</div>
<div>
{children}
</div>
</div>
</div>
);
}
function App() {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div>
<button onClick={() => setIsModalOpen(true)}>
모달 열기
</button>
<Modal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
title="알림"
>
<p>이것은 모달의 내용입니다.</p>
<p>모달 안에 어떤 내용이든 넣을 수 있습니다.</p>
<div>
<button
onClick={() => setIsModalOpen(false)}
>
확인
</button>
</div>
</Modal>
</div>
);
}
2.3 Props 전달 패턴
2.3.1 Props 전개 연산자
function Button({ children, ...props }) {
return (
<button
{...props}
>
{children}
</button>
);
}
function App() {
const handleClick = () => {
alert('버튼이 클릭되었습니다!');
};
return (
<div>
<Button onClick={handleClick}>클릭하세요</Button>
<Button onClick={handleClick} disabled>비활성화된 버튼</Button>
<Button
onClick={handleClick}
>
빨간 버튼
</Button>
</div>
);
}
2.3.2 조건부 Props 전달
function Card({ title, content, isHighlighted = false, onClick }) {
return (
<div
onClick={onClick}
>
<h3>
{title}
</h3>
<p>{content}</p>
</div>
);
}
function App() {
const handleCardClick = (cardTitle) => {
alert(`${cardTitle} 카드가 클릭되었습니다!`);
};
return (
<div>
<Card
title="일반 카드"
content="이것은 일반적인 카드입니다."
/>
<Card
title="강조된 카드"
content="이것은 강조된 카드입니다."
isHighlighted={true}
onClick={() => handleCardClick('강조된 카드')}
/>
<Card
title="클릭 가능한 카드"
content="이 카드는 클릭할 수 있습니다."
onClick={() => handleCardClick('클릭 가능한 카드')}
/>
</div>
);
}
2.4 고급 Children 활용
2.4.1 Children 검증 및 조작
import React from 'react';
function TabContainer({ children, activeTab = 0 }) {
const childrenArray = React.Children.toArray(children);
return (
<div>
<div>
{childrenArray.map((child, index) => (
<button
key={index}
>
탭 {index + 1}
</button>
))}
</div>
<div>
{childrenArray[activeTab]}
</div>
</div>
);
}
function Tab({ children }) {
return <div>{children}</div>;
}
function App() {
return (
<div>
<TabContainer activeTab={0}>
<Tab>
<h3>첫 번째 탭 내용</h3>
<p>이것은 첫 번째 탭의 내용입니다.</p>
</Tab>
<Tab>
<h3>두 번째 탭 내용</h3>
<p>이것은 두 번째 탭의 내용입니다.</p>
</Tab>
<Tab>
<h3>세 번째 탭 내용</h3>
<p>이것은 세 번째 탭의 내용입니다.</p>
</Tab>
</TabContainer>
</div>
);
}
2.4.2 Render Props 패턴
function DataFetcher({ render }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// 실제로는 API를 호출하겠지만, 여기서는 시뮬레이션
setTimeout(() => {
setData([
{ id: 1, name: '김개발', role: '프론트엔드' },
{ id: 2, name: '이디자인', role: 'UI/UX' },
{ id: 3, name: '박백엔드', role: '백엔드' }
]);
setLoading(false);
}, 2000);
}, []);
return render({ data, loading });
}
function UserList() {
return (
<DataFetcher
render={({ data, loading }) => (
<div>
<h2>사용자 목록</h2>
{loading ? (
<p>데이터를 불러오는 중...</p>
) : (
<ul>
{data.map(user => (
<li key={user.id}>
{user.name} - {user.role}
</li>
))}
</ul>
)}
</div>
)}
/>
);
}
function UserCards() {
return (
<DataFetcher
render={({ data, loading }) => (
<div>
<h2>사용자 카드</h2>
{loading ? (
<p>데이터를 불러오는 중...</p>
) : (
<div>
{data.map(user => (
<div
key={user.id}
>
<h4>{user.name}</h4>
<p>{user.role}</p>
</div>
))}
</div>
)}
</div>
)}
/>
);
}
function App() {
return (
<div>
<UserList />
<hr />
<UserCards />
</div>
);
}
2.5 실습: 재사용 가능한 카드 시스템
Props와 Children을 활용한 카드 시스템을 만들어봅시다:
import { useState } from 'react';
function Card({
title,
children,
variant = 'default',
size = 'medium',
onClick,
style = {}
}) {
const variants = {
default: {
backgroundColor: 'white',
borderColor: '#ddd'
},
primary: {
backgroundColor: '#007bff',
borderColor: '#007bff',
color: 'white'
},
success: {
backgroundColor: '#28a745',
borderColor: '#28a745',
color: 'white'
},
warning: {
backgroundColor: '#ffc107',
borderColor: '#ffc107',
color: '#212529'
}
};
const sizes = {
small: { padding: '10px', minWidth: '200px' },
medium: { padding: '20px', minWidth: '250px' },
large: { padding: '30px', minWidth: '300px' }
};
const cardStyle = {};
const [isHovered, setIsHovered] = useState(false);
return (
<div
onClick={onClick}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{title && (
<h3>
{title}
</h3>
)}
{children}
</div>
);
}
function CardHeader({ children }) {
return (
<div>
{children}
</div>
);
}
function CardBody({ children }) {
return (
<div>
{children}
</div>
);
}
function CardFooter({ children }) {
return (
<div>
{children}
</div>
);
}
function App() {
const handleCardClick = (cardType) => {
alert(`${cardType} 카드가 클릭되었습니다!`);
};
return (
<div>
<h1>카드 시스템 예제</h1>
<div>
<Card title="기본 카드" size="small">
<p>기본적인 카드입니다.</p>
</Card>
<Card
title="Primary 카드"
variant="primary"
onClick={() => handleCardClick('Primary')}
>
<p>클릭 가능한 파란색 카드입니다.</p>
</Card>
<Card title="Success 카드" variant="success" size="large">
<p>성공을 나타내는 녹색 카드입니다.</p>
<p>더 큰 크기로 설정되어 있습니다.</p>
</Card>
</div>
<div>
<Card title="복잡한 카드 구조">
<CardHeader>
<h4>제품 정보</h4>
<span>⭐⭐⭐⭐⭐</span>
</CardHeader>
<CardBody>
<p>이 제품은 매우 우수한 품질을 자랑합니다.</p>
<ul>
<li>고품질 소재</li>
<li>합리적인 가격</li>
<li>A/S 보장</li>
</ul>
</CardBody>
<CardFooter>
<button>
구매하기
</button>
<button>
찜하기
</button>
</CardFooter>
</Card>
<Card
variant="warning"
onClick={() => handleCardClick('Warning')}
>
<CardHeader>
<h4>⚠️ 주의사항</h4>
</CardHeader>
<CardBody>
<p>이 작업을 수행하기 전에 다음 사항을 확인하세요:</p>
<ol>
<li>모든 파일이 저장되었는지 확인</li>
<li>백업이 완료되었는지 확인</li>
<li>권한이 충분한지 확인</li>
</ol>
</CardBody>
<CardFooter>
<small>클릭하여 자세한 내용을 확인하세요</small>
</CardFooter>
</Card>
</div>
</div>
);
}
export default App;
2.6 정리
Props와 Children의 고급 활용법을 학습했습니다:
- Children을 통한 컴포넌트 조합으로 재사용성을 높일 수 있습니다
- Props 전개 연산자로 편리하게 Props를 전달할 수 있습니다
- 조건부 Props 전달로 동적인 컴포넌트를 만들 수 있습니다
- React.Children API로 Children을 조작할 수 있습니다
- Render Props 패턴으로 로직을 재사용할 수 있습니다
다음 장에서는 이벤트 처리에 대해 자세히 알아보겠습니다.