[React] 컴포넌트
개요
컴포넌트(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줄 이상)
- 독립적으로 테스트하고 싶을 때
- 다른 페이지에서도 재사용 가능할 때