DEV/React

[React 개발 기초] 6. children

develop-ch94 2026. 8. 10. 17:09
학습 목표: 컴포넌트를 박스처럼 만들고, 그 속에 내용을 자유롭게 담는 법을 배움

(1) children 받아쓰기

children은 특별한 이름의 Props임(고정임)

function Button({ children }) {
  return <button>{children}</button>;
}

// 사용
<Button>저장하기</Button>
<Button>삭제하기</Button>
<Button>특별 버튼</Button>

(2) Props vs children - 언제 뭘 쓸까?

📛 Props: 정해진 데이터 전달

<ProductCard
  name="사과"
  price={1000}
  imageUrl="apple.jpg"
/>
  • 각  props가 역할이 정해져 있음(name, price, imageUrl)
  • 주로 값(문자열, 숫자, 불린) 전달
  • 컴포넌트마다 미리 정의된 슬롯에 꽂아넣는 느낌

 

📦 children: 자유로운 내용물 전달

<Card>
  <h2>무엇이든</h2>
  <p>넣어도 되는</p>
  <img src="... />
  <Button>자유 공간</Button>
</Card>
  • 정해진 구조가 없음
  • 텍스트, JSX, 다른 컴포넌트 뭐든 OK
  • 컴포넌트를 범용 컨테이너로 만들 때 유용

🎯 판단 기준

상황 추천
값만 넘기면 됨(이름, 가격) Props
여러 요소 / 복잡한 JSX children
버튼 텍스트, 제목 같은 단순 텍스트 children 권장
필수 데이터(사용자 정보 등) Props

 


(3) 실전 예제

예제 1: Card 컴포넌트 (가장 전형적)

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

 

다양하게 활용 가능

{/* 간단한 텍스트 */}
<Card>안녕하세요</Card>

{/* HTML 요소 */}
<Card>
  <h2>제목</h2>
  <p>내용</p>
</Card>

{/* 다른 컴포넌트 */}
<Card>
  <UserProfile user={user} />
</Card>

 

예제 2: Button 컴포넌트

function Button({ children, onClick, variant = 'primary' }) {
  return (
    <button 
      className={`btn btn-${variant}`}
      onClick={onClick}
    >
      {children}
    </button>
  );
}

 

사용

<Button onClick={handleSava}>저장</Button>
<Button variant="danger">삭제</Button>

{/* 이모지 + 텍스트 조합도 가능 */}
<Button>
  이메일 보내기
</Button>

 

예제 3: Modal 컴포넌트

function Modal({ children, isOpen, onClose }) {
  if (!isOpen) return null; // 열림 상태가 아니면 아무것도 안 보여줌
  
  return (
    <div className="modal-backdrop">
      <div className="modal">
        <button className="close" onClick={onClose}>x</button>
        {children}
      </div>
    </div>
  );
}

 

사용

<Modal isOpen={showModal} onClose={() => setShowModal(false)}>
  <h2>알림</h2>
  <p>정말 삭제하시겠습니까?</p>
  <button onClick={handleDelete}>확인</button>
</Modal>

(4) children + 다른 props 조합

children과 다른 props는 자유롭게 섞어 쓸 수 있음
function Panel({ title, children, footer }) {
  return (
    <div className="panel">
      <div className="panel-header">
        <h3>{title}</h3>
      </div>
      <div className="panel-body">
        {children} {/* 메인 컨텐츠 */}
      </div>
      {footer && (
        <div className="panel-footer">
          {footer}
        </div>
      )}
    </div>
  );
}

 

사용

<Panel
  title="사용자 정보"                    {/* Props로 정해진 값 */}
  footer={<button>저장</button>}          {/* Props로 JSX도 전달 가능! */}
>
  <input type="text" placeholder="이름" />      {/* children */}
  <input type="email" placeholder="이메일" />
</Panel>

(5) 자주 하는 안티패턴

❌ 안티패턴 1: 단순 텍스트에 text props 남용

// ❌ 어색함 - React답지 않음
function Button({ text, onClick }) {
  return <button onClick={onClick}>{text}</button>;
}
<Button text="저장" onClick={handleSave} />

// ✅ HTML처럼 자연스럽게
function Button({ children, onClick }) {
  return <button onClick={onClick}>{children}</button>;
}
<Button onClick={handleSave}>저장</Button>
원칙: 텍스트나 JSX는 children으로! 

 

❌ 안티패턴 2: 구조화된 데이터를 children으로

// ❌ 이런 건 Props로!
<UserCard>
  홍길동
  25
  개발자
</UserCard>

// ✅ 정해진 구조는 Props
<UserCard name="홍길동" age={25} job="개발자" />
문제점: children은 자유로운 내용에 써야 함. 정해진 필드가 있다면 Props가 맞음

 

❌ 안티패턴 3: children이 빈 경우를 안 챙기

// ❌ children이 없으면 빈 카드가 튀어나옴
function Card({ children }) {
  return <div className="card">{children}</div>;
}
<Card />   {/* 빈 카드 렌더링... */}

// ✅ 기본값 또는 안전 처리
function Card({ children = '내용 없음' }) {
  return <div className="card">{children}</div>;
}