BioPlayground

🧬
목록으로

React 기초 — 컴포넌트와 Props

React의 핵심인 컴포넌트와 Props 개념을 배우고, 재사용 가능한 UI를 조립하는 방법을 익힙니다.

중급
|
12
|
검증 완료 (2026-07)
React컴포넌트PropsJSXUI 조립
진행률0/32 (0%)

React 기초 — 컴포넌트와 Props

이 토픽을 마치면

React에서 컴포넌트를 만들고, Props로 데이터를 전달하며, 여러 컴포넌트를 조합해서 화면을 구성할 수 있습니다.


왜 React인가

순수 HTML과 JavaScript로도 웹 페이지를 만들 수 있습니다. 하지만 페이지가 복잡해지면 문제가 생깁니다:

html
<!-- 같은 카드 구조를 10번 반복해야 한다면? -->
<div class="card">
  <h3>첫 번째 항목</h3>
  <p>설명...</p>
</div>
<div class="card">
  <h3>두 번째 항목</h3>
  <p>설명...</p>
</div>
<!-- ... 8번 더 -->

HTML을 복사-붙여넣기하면 디자인을 바꿀 때 10군데를 모두 수정해야 합니다. React는 이 문제를 컴포넌트로 해결합니다 — 반복되는 UI 조각을 하나의 부품으로 만들어 재사용합니다.


컴포넌트란

컴포넌트는 UI를 반환하는 함수입니다.

jsx
function Card() {
  return (
    <div className="card">
      <h3>제목</h3>
      <p>설명입니다</p>
    </div>
  );
}

이것이 하나의 컴포넌트입니다. HTML처럼 생긴 이 문법은 JSX라고 합니다. JavaScript 안에 마크업을 작성할 수 있게 해주는 문법입니다. JSX는 브라우저가 직접 이해하지 못하므로, 빌드 과정에서 일반 JavaScript로 변환됩니다.

컴포넌트 이름은 반드시 대문자로 시작합니다. 소문자로 시작하면 React는 HTML 태그로 인식합니다.


컴포넌트 사용하기

만든 컴포넌트를 다른 컴포넌트 안에서 태그처럼 씁니다:

jsx
function App() {
  return (
    <div>
      <Card />
      <Card />
      <Card />
    </div>
  );
}

<Card />를 3번 쓰면 같은 UI가 3번 렌더링됩니다. 디자인을 바꾸고 싶으면 Card 함수 하나만 수정하면 됩니다.


Props — 컴포넌트에 데이터 전달하기

지금까지의 Card는 항상 같은 내용을 보여줍니다. 각 카드에 다른 데이터를 넣고 싶으면 Props(Properties의 줄임말)를 사용합니다.

jsx
function Card(props) {
  return (
    <div className="card">
      <h3>{props.title}</h3>
      <p>{props.description}</p>
    </div>
  );
}

function App() {
  return (
    <div>
      <Card title="HTML" description="웹의 뼈대" />
      <Card title="CSS" description="웹의 옷" />
      <Card title="JS" description="웹의 두뇌" />
    </div>
  );
}

{props.title} — JSX에서 중괄호 {}는 "여기에 JavaScript 값을 넣겠다"는 의미입니다. Props는 부모 컴포넌트가 자식 컴포넌트에게 일방향으로 전달하는 데이터입니다.


구조 분해 할당으로 Props 받기

props.title, props.description을 매번 쓰는 건 번거롭습니다. 실무에서는 구조 분해 할당을 씁니다:

jsx
function Card({ title, description }) {
  return (
    <div className="card">
      <h3>{title}</h3>
      <p>{description}</p>
    </div>
  );
}

함수 매개변수에서 { title, description }으로 바로 꺼냅니다. 의미는 동일하지만 코드가 깔끔해집니다.


Props의 다양한 타입

Props에는 문자열뿐 아니라 숫자, 배열, 객체, 함수까지 전달할 수 있습니다:

jsx
function UserProfile({ name, age, hobbies, onFollow }) {
  return (
    <div>
      <h2>{name} ({age}세)</h2>
      <ul>
        {hobbies.map((hobby, i) => (
          <li key={i}>{hobby}</li>
        ))}
      </ul>
      <button onClick={onFollow}>팔로우</button>
    </div>
  );
}

// 사용
<UserProfile
  name="철수"
  age={25}
  hobbies={["코딩", "게임", "독서"]}
  onFollow={() => alert("팔로우!")}
/>

문자열은 따옴표로, 그 외의 값은 중괄호 {}로 감싸서 전달합니다. 배열을 map()으로 순회하면서 리스트를 렌더링하는 패턴은 React에서 매우 자주 쓰입니다.


children — 특별한 Props

컴포넌트 태그 사이에 넣는 내용은 children이라는 특별한 Props로 전달됩니다:

jsx
function Container({ children }) {
  return (
    <div className="container">
      {children}
    </div>
  );
}

// 사용
<Container>
  <h1>제목</h1>
  <p>여기 들어가는 모든 것이 children입니다</p>
</Container>

children을 활용하면 레이아웃 컴포넌트를 만들 수 있습니다 — 바깥 틀은 고정하고, 안의 내용만 바꾸는 패턴입니다.


컴포넌트 분리 기준

언제 컴포넌트를 분리해야 할까요?

  1. 반복되는 UI 조각 → 컴포넌트로 추출
  2. 독립적인 기능 단위 → 컴포넌트로 분리
  3. 화면이 너무 길어질 때 → 섹션별로 분리
text
App
├── Header
├── Main
│   ├── SearchBar
│   └── CardList
│       ├── Card
│       ├── Card
│       └── Card
└── Footer

이렇게 트리 구조로 조합하는 것이 React의 핵심 아이디어입니다.


Props 기본값 설정

Props가 전달되지 않았을 때를 대비해서 기본값을 설정할 수 있습니다:

jsx
function Badge({ label = "NEW", color = "#3498db" }) {
  return (
    <span style={{ 
      backgroundColor: color, 
      color: "white", 
      padding: "4px 8px", 
      borderRadius: "4px",
      fontSize: "12px"
    }}>
      {label}
    </span>
  );
}

// 기본값 사용
<Badge />                        // "NEW" + 파란색
<Badge label="HOT" />            // "HOT" + 파란색
<Badge label="SALE" color="red" /> // "SALE" + 빨간색

기본값을 설정해두면, 컴포넌트를 사용하는 쪽에서 모든 Props를 일일이 넘기지 않아도 됩니다. 선택적으로 필요한 것만 지정하면 됩니다.


JSX에서 주의할 점

JSX는 HTML과 비슷하지만, 몇 가지 중요한 차이가 있습니다:

jsx
// 1. class 대신 className
<div className="container">  // ✅
<div class="container">      // ❌ class는 JavaScript 예약어

// 2. for 대신 htmlFor
<label htmlFor="email">이메일</label>  // ✅

// 3. 반드시 하나의 루트 요소로 감싸야 함
function Wrong() {
  return (
    <h1>제목</h1>      // ❌ 두 개의 루트
    <p>내용</p>
  );
}

function Right() {
  return (
    <>                  // ✅ Fragment로 감싸기
      <h1>제목</h1>
      <p>내용</p>
    </>
  );
}

// 4. 스타일은 객체로
<div style={{ backgroundColor: "red", fontSize: "16px" }}>
  // camelCase + 문자열 값
</div>

<></>Fragment라고 합니다. 불필요한 <div> 래퍼 없이 여러 요소를 묶을 수 있습니다.


조건부 렌더링

Props 값에 따라 다른 UI를 보여줄 수 있습니다:

jsx
function StatusBadge({ isOnline }) {
  return (
    <span>
      {isOnline ? "🟢 온라인" : "⚪ 오프라인"}
    </span>
  );
}

function Notification({ count }) {
  return (
    <div>
      알림
      {count > 0 && <span className="badge">{count}</span>}
    </div>
  );
}

&& 연산자는 왼쪽이 true일 때만 오른쪽을 렌더링합니다. 삼항 연산자는 true/false 양쪽 모두 보여줄 때 씁니다. 이 두 패턴이 React에서 조건부 렌더링의 대부분을 처리합니다.


핵심 정리

개념설명
컴포넌트UI를 반환하는 함수 (대문자 시작)
JSXJavaScript 안에 마크업을 쓰는 문법
Props부모→자식 단방향 데이터 전달
children태그 사이 내용을 전달하는 특별한 Props
구조 분해({ title }) 형태로 Props를 깔끔하게 받기
기본값({ label = "NEW" }) 형태로 미전달 대비
Fragment<>...</> 불필요한 wrapper div 제거

React를 처음 배울 때 가장 중요한 것은 "어떤 데이터가 어디서 어디로 흐르는가"를 파악하는 겁니다. Props는 항상 위에서 아래로 흐릅니다. 자식이 부모의 데이터를 바꾸고 싶으면 부모가 "이걸 호출하면 내 상태를 바꿔줄게"라는 함수를 Props로 내려줍니다 — 이것이 다음에 배울 **상태(State)**와 연결됩니다.


→ 바이오에 적용: DevBench — React Intro