React 8. Conditional Rendering

뚜루미·2024년 2월 28일

React

목록 보기
8/39
post-thumbnail

컴포넌트는 다양한 조건에 따라 다른 내용을 표시해야 하는 경우가 많습니다. React 에서는 if 조건문이나 && , ? : 연산자와 같은 JavaScript 구문을 사용하여 조건에 맞는 JSX를 렌더링합니다.

Conditionally returning 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 props은 false대신 true 로 설정되어 있습니다. 만약 isPacked={true} 인 경우 체크마크를 추가하고 싶은 경우 아래와 같이 if / else 조건문을 작성하면 됩니다.

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

isPacked props이 true 인 경우, 이 코드는 다른 JSX 트리를 반환합니다. 이 변경으로 이해 일부 items은 뒤에 체크마크를 표시합니다.

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에 의해 처리됩니다.

Conditionally returning nothing with null

어떤 상황에서는 아무것도 렌더링하고 싶지 않을 수도 있습니다. 예를 들어, 포장된 품목을 전혀 표시하고 싶지 않다고 가정해 보겠습니다. 컴포넌트는 무언가를 반환해야 합니다. 이 경우 null 을 반환할 수 있습니다.

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

isPackedtrue이면 컴포넌트는 아무것도 반환하지 않고 아닌 경우 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 컴포넌트를 조건부로 포함하거나 제외하는 경우가 더 많습니다.

Conditionally including JSX

이전 예시에서는 컴포넌트가 어떤 JSX 트리를 반환할지 제어했습니다.

// 아래 두 항목은 매우 유사합니다.
<li className="item">{name}</li>
<li className="item">{name}</li>

이러한 중복은 코드를 유지 관리하게 어렵게 만들 수 있습니다. className을 변경하고 싶다면 코드의 두 위치에서 작업을 수행합니다. 이러한 상황에서는 JSX를 조건부로 포함하여 코드를 좀 더 DRY(Don’t Repeat Yourself)하게 만들 수 있습니다.

Conditional (ternary) operator ( ? : )

JavaScript는 조건식을 작성하기 위한 간단한 구문(조건 연산자 또는 삼항 연산자)가 있습니다.

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

// 위 코드 대신 아래와 같이 작성할 수 있습니다.

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

🚨 if / else 조건문과 삼항 연산자는 완전히 동일한가요?

객체 지향 프로그래밍 배경에서 본다면, 두 예시는 서로 다른 2가지의 <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에서 마크업은 코드의 일부이므로 변수 및 함수와 같은 도구를 사용하여 복잡한 표현식을 정리할 수 있습니다.

Logical AND operator (&&)

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

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 && 표현식은 좌항(조건)이 참인 경우 우항의 값을 반환합니다. 만약 조건이 거짓인 경우 모든 표현식도 거짓이 되며 React는 falsenull 이나 undefined와 같은 JSX 트리의 구멍으로 간주하여 아무것도 렌더링하지 않습니다.

🚨 좌항에는 숫자를 넣으면 안됩니다.

조건을 테스트하기 위해 JavaScript은 자동으로 좌항은 Bool로 변환합니다. 그러나 좌항이 0이면 전체 표현식은 해당 값을 가져오고 React는 아무것도 아닌 것이 아니라 0을 렌더링합니다.

예를 들어, 일반 적인 실수는 messageCount && <p>New messages</p> 입니다.

messageCount 가 0일때 아무것도 렌더링하지 않는다고 가정하기 쉽지만 실제로는 0 자체를 렌더링합니다.

이러한 문제를 해결하기 위해서는 messageCount > 0 && <p>New messages</p> 같이 작성해야 합니다.

Conditionally assigning JSX to a variable

또 다른 방법은 if 조건문과 변수를 사용하는 것입니다. let을 사용하여 정의된 변수를 재할당할 수 있기 때문에 기본 컨텐츠를 할당할 수 있습니다.

let itemContent = name;

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

이러한 스타일은 가장 장황하지만 가장 유연합니다.

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 코드를 일고 작성하는 데 도움이 됩니다.

0개의 댓글