학습 자료

조건부 렌더링 — 보여줄지 말지


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.length0이다. 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강에서 본 조기 반환이다.

삼항 vs early return

삼항 연산자

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을 쓰면 위에서 아래로 읽힌다. 로딩, 에러, 빈 상태를 차례로 걸러내고 마지막에 정상 화면이 남는다.

위에서부터 걸러낸다
  1. 01

    로딩 중인가

    맞으면 스피너를 그리고 함수가 끝난다. 아래는 실행되지 않는다.

    if (isLoading) return <Spinner />;
  2. 02

    에러가 났는가

    여기까지 왔다면 로딩은 끝났다는 뜻이다.

  3. 03

    데이터가 비었는가

    로딩도 끝났고 에러도 없는데 데이터가 없는 경우다.

  4. 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>}
display: none vs 조건부 렌더링

CSS 로 숨김

요소는 존재한다

  • DOM 에 남아 있다
  • 안의 컴포넌트도 살아 있다
  • 상태가 유지된다
  • 자주 여닫는 것에 알맞다

조건부 렌더링

요소가 없다

  • DOM 에서 사라진다
  • 안의 컴포넌트가 사라진다
  • 상태도 사라진다
  • 무거운 것을 안 그릴 때 알맞다

모달을 조건부 렌더링으로 닫았다가 다시 열면 입력하던 값이 전부 지워져 있다. 컴포넌트가 통째로 사라졌기 때문이다. 대개는 그게 원하는 동작이지만, 아닐 때도 있다.

정리하면

  • JSX 중괄호에는 if문을 못 넣는다. 값이 되는 것만 들어간다.
  • 둘 중 하나면 삼항 연산자, 보여주거나 말거나면 &&.
  • && 앞에 숫자를 두지 않는다. 0은 화면에 그려진다.
  • 아무것도 안 그리려면 null을 반환한다.
  • 예외 상황은 early return으로 위에서 걸러낸다. 중첩이 사라지고 위에서 아래로 읽힌다.
  • 갈래가 셋 이상이면 변수에 담거나 객체로 매핑한다.
  • 조건부 렌더링은 컴포넌트를 없앤다. 상태도 함께 사라진다.

Part 2가 끝났다. 여기까지의 컴포넌트는 전부 받은 props를 그리기만 했다. 다음 강의부터 컴포넌트가 스스로 값을 기억하기 시작한다. state다.

조건부 렌더링 — 보여줄지 말지 — 디코드랩(DCODELAB)