2 분 소요

개요

컴포넌트(Component)는 React UI를 구성하는 독립적이고 재사용 가능한 최소 단위입니다. 마치 레고 블록처럼, 작은 컴포넌트들을 조합해 복잡한 UI를 만듭니다.


함수형 컴포넌트

현재 React의 표준 방식입니다. 일반 JavaScript 함수처럼 정의합니다.

// 1. 함수 선언식
function Welcome() {
  return <h1>안녕하세요!</h1>;
}

// 2. 화살표 함수 (동일한 결과)
const Welcome = () => {
  return <h1>안녕하세요!</h1>;
};

// 간단한 경우 암시적 반환
const Welcome = () => <h1>안녕하세요!</h1>;

규칙: 컴포넌트 이름은 반드시 대문자로 시작해야 합니다.
<welcome /> → HTML 태그로 인식
<Welcome /> → React 컴포넌트로 인식


컴포넌트 파일 구성

각 컴포넌트는 별도 파일로 분리하는 것이 일반적입니다.

src/
├── App.tsx              ← 루트 컴포넌트
└── components/
    ├── Header.tsx
    ├── Footer.tsx
    └── UserCard.tsx
// src/components/UserCard.tsx

function UserCard() {
  return (
    <div>
      <h2>사용자 카드</h2>
      <p>이름: Alice</p>
    </div>
  );
}

export default UserCard;  // 내보내기
// src/App.tsx

import UserCard from "./components/UserCard";  // 가져오기

function App() {
  return (
    <div>
      <UserCard />   {/* 컴포넌트 사용 */}
      <UserCard />   {/* 재사용 가능 */}
    </div>
  );
}

export default App;


컴포넌트 중첩

컴포넌트 안에 다른 컴포넌트를 넣어 계층 구조를 만듭니다.

function Avatar() {
  return <img src="/avatar.png" alt="아바타" width={50} />;
}

function UserInfo() {
  return (
    <div>
      <Avatar />      {/* Avatar 컴포넌트를 포함 */}
      <p>Alice</p>
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>사용자 목록</h1>
      <UserInfo />    {/* UserInfo 컴포넌트를 포함 */}
      <UserInfo />
    </div>
  );
}

주의: 컴포넌트 함수 안에 다른 컴포넌트를 정의하지 마세요. 성능 문제와 버그의 원인이 됩니다.

// ❌ 잘못된 방식: 렌더링마다 Inner 함수가 새로 생성됨
function Outer() {
  function Inner() {
    return <p>내부</p>;
  }
  return <Inner />;
}

// ✅ 올바른 방식: 파일 최상위 레벨에 정의
function Inner() {
  return <p>내부</p>;
}

function Outer() {
  return <Inner />;
}


export 방식

// 방식 1: default export (파일당 하나)
function Button() {
  return <button>클릭</button>;
}
export default Button;

// 사용할 때: 이름을 자유롭게 지정 가능
import Button from "./Button";
import MyButton from "./Button";  // 동일한 컴포넌트


// 방식 2: named export (여러 개 가능)
export function PrimaryButton() {
  return <button className="primary">확인</button>;
}
export function SecondaryButton() {
  return <button className="secondary">취소</button>;
}

// 사용할 때: 반드시 정확한 이름 사용
import { PrimaryButton, SecondaryButton } from "./Button";


컴포넌트 설계 원칙

단일 책임 원칙

하나의 컴포넌트는 한 가지 역할만 담당하도록 설계합니다.

// ❌ 너무 많은 역할을 하는 컴포넌트
function UserPage() {
  return (
    <div>
      {/* 헤더, 사용자 정보, 게시글 목록, 댓글, 푸터... 모두 한 곳에 */}
    </div>
  );
}

// ✅ 역할에 따라 분리
function UserPage() {
  return (
    <div>
      <Header />
      <UserProfile />
      <PostList />
      <Footer />
    </div>
  );
}

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

  • 같은 UI가 반복될 때
  • 한 컴포넌트가 너무 길어질 때 (200줄 이상)
  • 독립적으로 테스트하고 싶을 때
  • 다른 페이지에서도 재사용 가능할 때


관련 링크