컴포넌트(Component)는 UI의 한 조각을 캡슐화한 독립적인 단위입니다. React에서 컴포넌트는 props를 입력으로 받아 JSX를 반환하는 함수입니다. 버튼 하나일 수도 있고, 페이지 전체일 수도 있습니다.
컴포넌트 기반 설계의 핵심 목표는 UI를 독립적이고 재사용 가능한 조각으로 나누어 복잡도를 관리하는 것입니다.
React는 클래스형 컴포넌트와 함수형 컴포넌트를 모두 지원했지만, React 16.8에서 Hooks가 도입된 이후 함수형 컴포넌트가 표준이 되었습니다.
// 기본 함수형 컴포넌트
function Greeting({ name }) {
return <h1>안녕하세요, {name}님</h1>;
}
// 화살표 함수로도 작성 가능
const Greeting = ({ name }) => <h1>안녕하세요, {name}님</h1>;
함수형 컴포넌트의 규칙은 두 가지입니다.
null이어야 합니다.React에서 복잡한 UI는 작은 컴포넌트를 조합(Composition)하여 만듭니다. 상속보다 합성을 권장하는 것이 React의 공식 권고 사항입니다.
┌──────────────────────────────────┐
│ ProfileCard │
│ ┌──────────┐ ┌──────────────┐ │
│ │ Avatar │ │ UserInfo │ │
│ └──────────┘ │ ┌────────┐ │ │
│ │ │ Name │ │ │
│ │ └────────┘ │ │
│ │ ┌────────┐ │ │
│ │ │ Bio │ │ │
│ │ └────────┘ │ │
│ └──────────────┘ │
└──────────────────────────────────┘
function Avatar({ src, alt }) {
return <img src={src} alt={alt} className="avatar" />;
}
function UserInfo({ name, bio }) {
return (
<div>
<p>{name}</p>
<p>{bio}</p>
</div>
);
}
function ProfileCard({ user }) {
return (
<div className="card">
<Avatar src={user.avatarUrl} alt={user.name} />
<UserInfo name={user.name} bio={user.bio} />
</div>
);
}
children prop을 활용하면 컨테이너 역할의 컴포넌트를 만들 수 있습니다.
function Card({ children }) {
return <div className="card">{children}</div>;
}
// 사용
<Card>
<h2>제목</h2>
<p>내용</p>
</Card>
잘 설계된 컴포넌트는 다양한 맥락에서 재사용됩니다. 재사용성을 높이려면 컴포넌트가 특정 데이터 구조나 외부 상태에 의존하지 않고, 필요한 데이터를 props로 받아야 합니다.
// 재사용하기 어려운 예: 내부에서 전역 상태를 직접 참조
function UserName() {
return <span>{window.currentUser.name}</span>;
}
// 재사용하기 쉬운 예: 필요한 데이터를 props로 받음
function UserName({ name }) {
return <span>{name}</span>;
}
컴포넌트를 언제 분리할지 판단하는 기준은 다음과 같습니다.
반대로, 한 번만 쓰이는 단순한 UI 조각은 굳이 분리하지 않아도 됩니다. 과도한 분리는 오히려 파일 수만 늘리고 코드 흐름을 추적하기 어렵게 만듭니다.
컴포넌트는 React의 기본 구성 단위입니다. props를 입력받아 JSX를 반환하는 순수한 함수로 설계할수록 재사용성과 테스트 용이성이 높아집니다. 작고 독립적인 컴포넌트를 합성하여 복잡한 UI를 만드는 것이 React의 핵심 패턴입니다.