#07. React 컴포넌트
목차9
TL;DR
- 컴포넌트를 언제, 어떻게 작성하는가?
개요
예전에 HTML/CSS를 공부할 때, 자주 반복되는 항목들을 어떻게 감싸서 재활용할 수 있을까라는 고민을 종종 했었다.
이에 대한 대답은 컴포넌트(Component) 단위로의 분해가 될 수 있을 것 같다.
프론트엔드에서의 엄밀한 컴포넌트의 정의는 버튼, 텍스트 박스, Input 텍스트 필드처럼 화면을 구성하는 기본적인 최소단위 UI 부품들을 의미하는데,
(특히 Figma를 사용하는 디자이너들과) 대화하다보니, 지금은 그냥 “반복 재사용 가능한 요소” 정도로 넓게 받아들이고 있다.
When: 언제 나누는가?
무조건 컴포넌트를 잘게 나눌 필요는 없다.
단 한번만 사용될 요소인데 굳이 파일을 또 늘리는 것은 오버 엔지니어링이 될 수도 있으니까.
아래의 기준을 고려해보자 — 사실 뻔한 내용들이다:
- 같은 컴포넌트가 반복될 때
- 예를들어, 블로그에서 게시글 리스트를 보여줄 때, 각 항목은 재사용 가능한 컴포넌트를 사용하는 것이 좋다.
- 큰 페이지를 작은 단위로 쪼갤 때
- 가독성 + 나중에 비슷한 섹션을 사용할 때 쉽게 분리하기 위해
- 자주 바뀌는 요소일 때
- React는 state 변경 시, 그 컴포넌트와 하위 트리를 다시 그린다.
- 만약 자주 바뀌는 부분을 분리해놓는다면, re-render시 필요한 부분만 최소한으로 변경되도록 유도할 수 있다.
How to: 어떻게 만드는가?
- 바깥에
function하나 만들고 return에 JSX(마크업)를 담은 후- 쓰는 쪽에서
<함수명 />으로 부른다
여기서 주의할 점은, 기본 HTML의 태그들과 구분하기 위해 이름은 반드시 대문자로 시작해야 한다.
React가 첫 글자의 대소문자 여부로 커스텀 컴포넌트인지 기본 HTML 태그인지 구분하므로,
그냥 대문자로 시작하는 이름을 사용하자.
function Card() { return (<div>...</div>); }
<Card /> // 내가 만든 컴포넌트
<card /> // 그냥 HTML 태그로 취급됨
만약 별도의 파일에서 정의했다면, export로 외부에서 사용할 수 있게 선언해주고,
사용하는 측에서는 import로 불러와야한다.
매개변수는 props 하나뿐
컴포넌트 함수는 인자를 단 하나만 받으며, 이것이 props 객체이다.
아무리 여러 속성을 넘기더라도, React는 하나의 객체로 묶어서 내려준다.
관례적으로, 컴포넌트 함수는 받은 매개변수를 구조분해하여 사용한다.
<Card title="신발" price={120000} /> // 속성 2개를 넘김
// React가 { title, price }로 묶어 내려줌; 구조분해하여 사용
function Card({ title, price }) {
return <h4>{title} / {price}원</h4>;
}
구조분해가 강제 사항은 아니며, 그냥 단일 매개변수로 받은 후 꺼내쓰는 방식도 가능하기는 하다.
function Card( props ) {
return <h4>{props.title} / {props.price}원</h4>;
}
근데 나라면 구조분해 할 것 같긴 하다.
주의할 점
1. if 대신 삼항 (또는 &&)
JSX의 { }엔 표현식만 들어가서 if문을 직접 못 쓴다. 조건부 렌더링은 삼항이나 &&로 한다.
{isLoading ? <Spinner /> : <Content />}
{isError && <RetryButton />}
아무것도 안 그리고 싶으면 null을 쓴다.
{cond ? <X /> : null}, 혹은 컴포넌트 자체가 return null 하는 방식으로.
2. 반복은 .map() + key
반복문 대신 배열에 .map() 함수를 사용한다.
map 함수는 리스트 내 모든 요소들에 한번씩 적용되므로, 반복되는 UI 요소들을 그릴 때 유용하다.
이때 각 요소엔 key가 있어야 하는데, 이는 React가 항목을 등장 순서가 아니라 “정체성”으로 추적하기 위함이다.
// article은 { id, title, contents } 등으로 이루어졌다고 가정
{articles.map((article) => <ArticleListItem key={article.id} contents={article} />)}
이때 key에는 배열의 index보다는 데이터의 고유 id를 사용하는 것이 좋다.
만약 배열의 index가 사용될 경우, 배열의 정렬/삽입/삭제 등으로 순서가 바뀔 때, React가 엉뚱한 항목을 재사용할 수 있다.
Compose 기준으로, 가장 비슷한 사례가 LazyColumn이 아닐까 싶다.
LazyColumn의 경우 사용할 리스트 내 아이템 뿐 아니라 key도 요구하는데,
이는 항목의 순서가 런타임 중 변경되더라도 올바른 데이터를 참조하기 위한 식별자로 사용하기 때문이다.
(참고)
결론
몇가지 규칙만 제외하면, 다른 스택에서도 늘 보이는 모듈화와 관련된 부분이다.
다만 다른 부분에서는 테스트나 재사용성, 가독성의 측면이 강조된다면,
프론트엔드 측에서는 “Re-render 시 불필요한 연산을 아끼기 위해”서의 측면도 있다는 점도 알아두면 좋을 것 같다.
