컴포넌트 — 어디서 잘라야 하나
Article
2강에서 컴포넌트는 그냥 함수라고 했다. 문법은 그게 전부다.
어려운 건 문법이 아니라 어디서 자를 것인가다. 너무 잘게 나누면 파일만 늘어나고, 안 나누면 한 파일이 500줄이 된다.
나누지 않으면 어떻게 되나
상품 목록 페이지를 한 컴포넌트에 다 넣어본다.
function ProductPage() {
return (
<div>
<header>
<img src="/logo.png" alt="로고" />
<nav>…메뉴 열 개…</nav>
</header>
<section>
<div className="card">
<img src="/p1.png" alt="상품1" />
<h3>노트북</h3>
<p>1,200,000원</p>
<button>담기</button>
</div>
<div className="card">
<img src="/p2.png" alt="상품2" />
<h3>마우스</h3>
<p>30,000원</p>
<button>담기</button>
</div>
</section>
<footer>…</footer>
</div>
);
}
문제가 눈에 보인다.
- 01
같은 마크업이 반복된다
카드가 열 개면 같은 코드를 열 번 쓴다. 디자인이 바뀌면 열 군데를 고친다.
- 02
전체를 읽어야 한 곳을 안다
버튼 하나 고치려고 400줄을 스크롤한다.
- 03
이름이 없다
div.card가 무엇인지 마크업을 읽어야 안다.ProductCard라는 이름이 있으면 읽을 필요가 없다.
나누는 기준
파일을 나누는 게 목적이 아니다. 하나의 컴포넌트는 하나의 일만 한다.
- ProductPage
- Header
- ProductList
- ProductCard
- Footer
이렇게 자르고 나면 ProductPage는 이렇게 짧아진다.
function ProductPage() {
return (
<>
<Header />
<ProductList />
<Footer />
</>
);
}
페이지가 무엇으로 이뤄졌는지 한눈에 보인다. 세부 내용은 각자의 파일에 있다.
언제 자르지 않나
성급하게 나누는 것도 문제다.
자른다
이럴 때 나눈다
- 같은 마크업이 두 번 이상 반복된다
- 이름이 자연스럽게 떠오른다
- 다른 화면에서도 쓸 것 같다
- 한 컴포넌트가 화면을 채운다
둔다
아직 나누지 않는다
- "나중에 쓸 것 같아서"
- 이름이 안 떠오른다
- props 를 다섯 개 넘게 넘겨야 한다
- 잘랐더니 오히려 읽기 어렵다
props를 다섯 개 넘게 넘겨야 한다면 잘못 자른 것이다. 조각이 부모에게 너무 많이 의존한다는 뜻이다. 5강에서 props를 배우고 나면 이 감각이 생긴다.
한 파일에 여러 컴포넌트를 둬도 되나
된다. 문법적으로 제한이 없다.
function Avatar({ src }) {
return <img className="avatar" src={src} alt="" />;
}
function UserCard({ user }) {
return (
<div className="card">
<Avatar src={user.image} />
<span>{user.name}</span>
</div>
);
}
export default UserCard;
Avatar가 UserCard에서만 쓰인다면 같은 파일에 둔다. 파일을 늘리지 않으면서 마크업을 정리할 수 있다.
다른 곳에서도 쓰게 되면 그때 파일을 분리한다. 미리 나누지 않는다.
절대 하면 안 되는 것
컴포넌트를 다른 컴포넌트 안에 정의하는 것이다.
function App() {
function Greeting() {
return <p>안녕</p>;
}
return <Greeting />;
}
동작은 한다. 그런데 App이 다시 실행될 때마다 Greeting이 새 함수로 다시 만들어진다. 자바스크립트 편 11강에서 "함수는 값"이라고 했으니 매번 다른 값이다.
React는 그걸 완전히 다른 컴포넌트로 보고 화면을 통째로 새로 그린다. 안에 있던 상태도 전부 날아간다.
파일과 폴더
정답은 없지만 흔히 쓰는 방식이 있다.
- src
- components
- Button.jsx
- Avatar.jsx
- pages
- ProductPage.jsx
- App.jsx
- main.jsx
- components
파일명은 컴포넌트 이름과 똑같이, 대문자로 시작한다. ProductCard.jsx 안에는 ProductCard가 있다. 찾기 쉽다.
| 규칙 | 예 |
|---|---|
| 컴포넌트 이름 = 파일 이름 | ProductCard.jsx |
| 대문자로 시작 (파스칼 케이스) | SearchBar.jsx |
| 기본 내보내기 하나 | export default ProductCard |
| 폴더는 역할로 나눈다 | components / pages |
정리하면
- 컴포넌트를 나누는 건 파일을 늘리려는 게 아니다. 반복을 없애고 이름을 붙이려는 것이다.
- 이름이 자연스럽게 떠오르면 자를 때다.
Wrapper밖에 안 떠오르면 아직 아니다. - 작을수록 좋은 게 아니다. 의미 단위로 자른다.
props를 다섯 개 넘게 넘겨야 한다면 잘못 자른 신호다.- 컴포넌트 안에 컴포넌트를 정의하지 않는다. 상태가 날아가고 원인을 찾기 어렵다.
- 파일명과 컴포넌트 이름을 맞추고, 대문자로 시작한다.
다음 강의에서는 부모가 자식에게 값을 건네는 방법, props를 배운다. 지금까지의 컴포넌트는 항상 같은 화면만 그렸다.