조건부 렌더링 — 보여줄지 말지
Article
로그인했으면 프로필을, 안 했으면 로그인 버튼을 보여준다. 화면을 조건에 따라 다르게 그리는 일은 끝없이 나온다.
3강에서 JSX 중괄호에는 값이 되는 것만 넣을 수 있다고 했다. if문은 값을 만들지 않는다. 그래서 다른 방법이 필요하다.
삼항 연산자 — 둘 중 하나
가장 흔한 방법이다. 자바스크립트 편 8강에서 배운 그것이다.
function Header({ user }) {
return (
<header>
{user ? <Profile user={user} /> : <LoginButton />}
</header>
);
}
값을 내놓으므로 중괄호에 들어간다. 짧고 읽기 좋다.
속성 값에도 쓸 수 있다.
<button className={isActive ? "btn active" : "btn"}>
{isLoading ? "저장 중…" : "저장"}
</button>
&& — 보여주거나 말거나
"조건이 참일 때만 보여준다"면 else가 필요 없다.
function Cart({ items }) {
return (
<div>
<h2>장바구니</h2>
{items.length > 0 && <Badge count={items.length} />}
</div>
);
}
자바스크립트 편 6강의 단축 평가다. 왼쪽이 거짓이면 오른쪽을 보지 않고 거짓을 돌려준다. false는 화면에 그려지지 않으므로 아무것도 안 나온다.
여기 3강에서 경고한 함정이 있다. 다시 짚는다.
{items.length && <Badge />}
items가 빈 배열이면 items.length는 0이다. 0 && ...은 0을 돌려주고, React는 0을 화면에 그린다.
| 값 | 화면에 | 왜 |
|---|---|---|
| false && <A /> | (안 나옴) | false 는 무시된다 |
| null && <A /> | (안 나옴) | null 은 무시된다 |
| 0 && <A /> | 0 | 숫자는 그려진다 |
| "" && <A /> | (안 나옴) | 빈 문자열은 무시된다 |
| items.length > 0 && <A /> | 정상 | boolean 이 된다 |
null 을 반환한다
컴포넌트가 아무것도 안 그려야 한다면 null을 돌려준다.
function Alert({ message }) {
if (!message) return null;
return <div className="alert">{message}</div>;
}
if문을 JSX 밖에서 쓴 것이 핵심이다. return 위쪽은 그냥 자바스크립트라 무엇이든 쓸 수 있다.
이 방식을 early return이라 부른다. 자바스크립트 편 10강에서 본 조기 반환이다.
삼항 연산자
JSX 안에서
- 두 갈래가 둘 다 보일 때
- 작은 조각을 바꿀 때
- 속성 값을 고를 때
- 겹치면 읽기 어렵다
early return
JSX 밖에서
- 예외 상황을 먼저 걸러낼 때
- 화면 전체가 달라질 때
if문을 자유롭게 쓴다- 중첩이 사라진다
여러 상태를 다룰 때 진가가 드러난다.
function UserProfile({ isLoading, error, user }) {
if (isLoading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
if (!user) return <Empty />;
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}
삼항으로 쓰면 세 겹으로 중첩된다. early return을 쓰면 위에서 아래로 읽힌다. 로딩, 에러, 빈 상태를 차례로 걸러내고 마지막에 정상 화면이 남는다.
- 01
로딩 중인가
맞으면 스피너를 그리고 함수가 끝난다. 아래는 실행되지 않는다.
if (isLoading) return <Spinner />; - 02
에러가 났는가
여기까지 왔다면 로딩은 끝났다는 뜻이다.
- 03
데이터가 비었는가
로딩도 끝났고 에러도 없는데 데이터가 없는 경우다.
- 04
정상 화면
예외를 전부 걸러냈으니 여기서는
user가 있다고 확신할 수 있다.
마지막 줄에서 user?.name처럼 물음표를 붙일 필요가 없다. 위에서 이미 걸러냈기 때문이다.
변수에 담는다
JSX는 값이므로 변수에 담아뒀다가 나중에 쓸 수 있다.
function Status({ code }) {
let icon;
if (code === "success") {
icon = <CheckIcon />;
} else if (code === "warning") {
icon = <WarnIcon />;
} else {
icon = <InfoIcon />;
}
return (
<div className="status">
{icon}
<span>{code}</span>
</div>
);
}
if / else if를 마음껏 쓰면서 JSX는 깔끔하게 유지된다. 갈래가 셋 이상일 때 좋다.
객체로 매핑하면 더 짧아진다.
const ICONS = {
success: <CheckIcon />,
warning: <WarnIcon />,
info: <InfoIcon />,
};
function Status({ code }) {
return (
<div className="status">
{ICONS[code] ?? <InfoIcon />}
<span>{code}</span>
</div>
);
}
자바스크립트 편 17강의 대괄호 표기법과 6강의 ??다. 조건이 늘어나도 코드는 안 늘어난다.
감추기와 안 그리기는 다르다
CSS로 숨기는 것과 React가 아예 안 그리는 것은 다르다.
<div style={{ display: isOpen ? "block" : "none" }}>…</div>
{isOpen && <div>…</div>}
CSS 로 숨김
요소는 존재한다
- DOM 에 남아 있다
- 안의 컴포넌트도 살아 있다
- 상태가 유지된다
- 자주 여닫는 것에 알맞다
조건부 렌더링
요소가 없다
- DOM 에서 사라진다
- 안의 컴포넌트가 사라진다
- 상태도 사라진다
- 무거운 것을 안 그릴 때 알맞다
모달을 조건부 렌더링으로 닫았다가 다시 열면 입력하던 값이 전부 지워져 있다. 컴포넌트가 통째로 사라졌기 때문이다. 대개는 그게 원하는 동작이지만, 아닐 때도 있다.
정리하면
- JSX 중괄호에는
if문을 못 넣는다. 값이 되는 것만 들어간다. - 둘 중 하나면 삼항 연산자, 보여주거나 말거나면
&&. &&앞에 숫자를 두지 않는다.0은 화면에 그려진다.- 아무것도 안 그리려면
null을 반환한다. - 예외 상황은 early return으로 위에서 걸러낸다. 중첩이 사라지고 위에서 아래로 읽힌다.
- 갈래가 셋 이상이면 변수에 담거나 객체로 매핑한다.
- 조건부 렌더링은 컴포넌트를 없앤다. 상태도 함께 사라진다.
Part 2가 끝났다. 여기까지의 컴포넌트는 전부 받은 props를 그리기만 했다. 다음 강의부터 컴포넌트가 스스로 값을 기억하기 시작한다. state다.