조건부 렌더링

컴포넌트는 조건에 따라 다른 항목을 표시해야 하는 경우가 많습니다. 리액트는 if 문, &&? : 연산자와 같은 자바스크립트 문법을 사용하여 조건부로 JSX를 렌더링할 수 있습니다.

You will learn

  • 조건에 따라 다른 JSX를 반환하는 방법
  • JSX 조각을 조건부로 포함하거나 제외하는 방법
  • React 코드에서 흔히 볼 수 있는 조건부 문법

조건부로 JSX 반환하기

짐을 챙겼는지 안 챙겼는지 표시할 수 있는 여러 개의 Item을 렌더링하는 PackingList 컴포넌트가 있다고 가정해봅시다.

function Item({ name, isPacked }) {
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

Item 컴포넌트 중 일부는 isPacked prop이 false가 아닌 true로 설정되어 있습니다. isPacked={true}인 경우 짐을 챙긴 항목에 체크 표시(✔)를 추가하려고 합니다.

다음과 같이 if/else으로 작성할 수 있습니다.

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

isPacked prop이 true이면 이 코드는 다른 JSX 트리를 반환합니다. 이로 인해 일부 항목은 끝에 체크 표시가 있습니다.

function Item({ name, isPacked }) {
  if (isPacked) {
    return <li className="item">{name}</li>;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

각각의 경우를 수정해보고 반환 결과가 어떻게 달라지는지 확인해 보세요!

JavaScript의 ifreturn 문으로 분기 로직을 만드는 방법을 살펴보세요. React에서 제어 흐름(예: 조건문)은 JavaScript로 처리합니다.

조건부로 null을 사용하여 아무것도 반환하지 않기

어떤 경우에는 아무것도 렌더링하고 싶지 않을 수 있습니다. 예를 들어, 짐을 챙긴 항목을 전혀 보여주지 않는다고 가정해보세요. 컴포넌트는 반드시 무언가를 반환해야 하는데 이 경우에 null을 반환할 수 있습니다. 다음과 같이 말이죠.

if (isPacked) {
return null;
}
return <li className="item">{name}</li>;

isPackedtrue라면 컴포넌트는 아무것도 반환하지 않지만, false라면 JSX가 반환될 것입니다.

function Item({ name, isPacked }) {
  if (isPacked) {
    return null;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

실제로 컴포넌트에서 null을 반환하는 것은 개발자가 렌더링하려고 할 때 놀랄 수 있기 때문에 흔한 경우는 아닙니다. 더 자주, 부모 컴포넌트 JSX에 컴포넌트를 조건부로 포함하거나 제외할 수 있습니다. 다음과 같이 해보세요!

조건부로 JSX 포함시키기

이전 예제에서는 어떤 항목(있는 경우)을 제어했습니다. 컴포넌트에 의해 JSX 트리가 반환되었습니다. 렌더링 된 출력 결과에서 이미 일부 중복이 발견되었을 수 있습니다.

<li className="item">{name}</li>

이것은 아래와 매우 비슷합니다.

<li className="item">{name}</li>

두 조건부 분기가 모두 <li className="item">...</li>를 반환합니다.

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

이 중복코드가 나쁘지는 않지만, 코드를 유지 보수하기 더 어렵게 만들 수 있습니다. className을 바꾸고 싶다면 어떻게 해야 할까요? 코드상 두 군데를 수정해야 합니다! 이러한 상황에서 조건부로 약간의 JSX를 포함해 코드를 더 DRY(덜 반복적이게) 하게 만들 수 있습니다.

삼항 조건 연산자 (? :)

JavaScript는 조건 연산자 또는 “삼항 조건 연산자”라는 조건식을 작성하기 위한 간단한 문법이 있습니다.

이 코드 대신,

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

다음과 같이 작성할 수 있습니다.

return (
<li className="item">
{isPacked ? name + ' ✔' : name}
</li>
);

isPacked가 참이면 (?) name + ' ✔'을 렌더링하고, 그렇지 않으면 (:) name을 렌더링 한다.” 라고 읽을 수 있습니다.

Deep Dive

두 예제는 완전히 동일할까요?

<li>의 두 가지 다른 “인스턴스”를 만들 수 있기 때문에 객체 지향 프로그래밍에서는 위의 두 예가 미묘하게 다르다고 생각할 수 있습니다. 그러나 JSX 엘리먼트는 내부 상태를 보유하지 않으며 실제 DOM 노드가 아니기 때문에 “인스턴스”가 아닙니다. 이것은 청사진처럼 간단한 설명입니다. 따라서 위의 두 가지 예시 코드는 실제로 완전히 동일합니다. 상태를 보존하고 초기화하기에서는 이 기능이 어떻게 작동하는지 자세히 설명합니다.

이제 완성된 항목의 텍스트를 <del>과 같은 다른 HTML 태그로 줄 바꿈 하여 삭제하려고 합니다. 더 많은 JSX를 중첩하기 쉽도록 새로운 줄과 괄호를 추가할 수 있습니다.

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {isPacked ? (
        <del>
          {name + ' ✔'}
        </del>
      ) : (
        name
      )}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

이 스타일은 간단한 조건에 잘 어울리지만, 적당히 사용하는 게 좋습니다. 중첩된 조건부 마크업이 너무 많아 컴포넌트가 지저분해질 경우 자식 컴포넌트를 추출하여 정리하세요. React에서 마크업은 코드의 일부이므로 변수 및 함수와 같은 도구를 사용하여 복잡한 식을 정리할 수 있습니다.

논리 AND 연산자 (&&)

또 다른 일반적인 손쉬운 방법은 JavaScript 논리 AND (’&&’) 연산자입니다. React 컴포넌트에서는 조건이 참일 때 일부 JSX를 렌더링하거나 그렇지 않으면 아무것도 렌더링하지 않을 때 를 나타내는 경우가 많습니다. 다음과 같이 &&를 사용하면 isPackedtrue인 경우에만 조건부로 체크 표시를 렌더링할 수 있습니다.

return (
<li className="item">
{name} {isPacked && '✔'}
</li>
);

이것을 “isPacked이면 (&&) 체크 표시를 렌더링하고, 그렇지 않으면 아무것도 렌더링하지 않습니다.”라고 읽을 수 있습니다.

자, 잘 작동합니다.

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✔'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

JavaScript && 표현식은 왼쪽(조건)이 true이면 오른쪽(체크 표시)의 값을 반환합니다. 그러나 조건이 false이면 전체 표현 식이 false가 됩니다. React는 falsenull 또는 undefined처럼 JSX 트리의 “구멍”으로 간주하고 그 자리에 아무것도 렌더링하지 않습니다.

주의하세요!

&&의 왼쪽에 숫자를 두지 마세요.

조건을 테스트하기 위해 JavaScript는 자동으로 왼쪽을 부울로 변환합니다. 그러나 왼쪽이 0이면 전체 식이 (0)을 얻게 되고, 리액트는 아무것도 아닌 0을 렌더링할 것입니다.

예를 들어, 흔하게 하는 실수로 messageCount && <p>New messages</p>와 같은 코드를 작성하는 것입니다. 메시지 카운트가 0일 때 아무것도 렌더링하지 않는다고 쉽게 추측할 수 있지만, 실제로는 0 자체를 렌더링합니다!

이 문제를 해결하려면 messageCount > 0 && <p>New messages</p> 처럼 왼쪽을 부울로 만드세요.

변수에 조건부로 JSX를 할당하기

위와 같은 방법이 일반 코드를 작성하는 데 방해가 되면 if 문과 변수를 사용하세요. let으로 정의된 변수는 재할당할 수 있으므로 표시할 기본 내용인 이름을 먼저 대입하세요.

let itemContent = name;

if 문을 사용하여 isPackedtrue인 경우 JSX 표현식을 itemContent에 다시 할당합니다.

if (isPacked) {
itemContent = name + " ✔";
}

중괄호는 “JavaScript로 들어가는 창”을 엽니다. 반환된 JSX 트리에 중괄호를 사용하고 이전에 계산된 식을 JSX 내부에 중첩하여 변수를 포함합니다.

<li className="item">
{itemContent}
</li>

이 스타일은 가장 장황하면서도 가장 유연합니다. 코드가 잘 작동 중입니다.

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = name + " ✔";
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

이전과 같이 텍스트뿐만 아니라 임의의 JSX에도 작동합니다.

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = (
      <del>
        {name + " ✔"}
      </del>
    );
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

JavaScript가 익숙하지 않다면, 처음에는 이런 다양한 코드 스타일이 낯설게 보일 수 있습니다. 그러나 이러한 코드를 학습한다면 React 컴포넌트뿐만 아니라 어떤 JavaScript 코드도 읽고 쓸 수 있습니다! 처음에 가장 선호하는 것을 선택해보고, 만약 다른 코드들이 어떻게 작동하는지를 잊어버린다면 이 문서를 다시 참고하세요.

Recap

  • React에서 JavaScript로 분기 로직을 제어합니다.
  • 조건부로 if 문과 함께 JSX 식을 반환할 수 있습니다.
  • 조건부로 일부 JSX를 변수에 저장한 다음 중괄호를 사용하여 다른 JSX에 포함할 수 있습니다.
  • JSX에서 {cond ? <A /> : <B />}cond이면 <A />를 렌더링하고, 그렇지 않으면 <B />를 렌더링합니다.” 를 의미합니다.
  • JSX에서 {cond && <A />}cond이면, <A />를 렌더링하되, 그렇지 않으면 아무것도 렌더링하지 않습니다.” 를 의미합니다.
  • 위 예시는 흔한 방법이지만, if를 선호한다면 사용하지 않아도 됩니다.

Challenge 1 of 3:
? :를 사용하여 완료되지 않은 항목의 아이콘을 표시합니다.

isPackedtrue가 아닌 경우 조건부 연산자(cond ? a : b)를 사용하여 ❌를 렌더링합니다.

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✔'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}