Renderowanie warunkowe

Twoje komponenty zazwyczaj będą wyświetlały różne informacje w zależności od różnych warunków. W Reakcie możesz renderować warunkowo JSX używając składni javascriptowej, takiej jak warunek if czy operatory && i ? :.

W tej sekcji dowiesz się

  • Jak zwrócić różny kod JSX w zależności od warunku
  • Jak warunkowo wyświetlić lub wykluczyć część JSX-a
  • Powszechne skróty składni warunkowej, które napotkasz w bazach kodu reactowego

Warunkowe zwracanie JSX-a

Załóżmy, że masz komponent PackingList renderujący kilka przedmiotów Item, które mogą być oznaczone jako spakowane isPacked={true} lub niespakowane isPacked={false}:

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

export default function PackingList() {
  return (
    <section>
      <h1>Lista rzeczy do spakowania Sally Ride</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Skafander kosmiczny" 
        />
        <Item 
          isPacked={true} 
          name="Hełm ze złotym liściem" 
        />
        <Item 
          isPacked={false} 
          name="Zdjęcie Tam" 
        />
      </ul>
    </section>
  );
}

Zauważ, że dla niektórych komponentów Item właściwość isPacked ustawiono na true zamiast false. Chcielibyśmy, żeby przy spakowanych przedmiotach, które mają ustawione isPacked={true}, wyświetlał się “ptaszek” (✔).

Możesz to zapisać za pomocą warunku if/else w ten sposób:

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

Jeśli właściwość isPacked jest ustawiona na true, ten kod zwróci odmienne drzewo JSX. Wraz z tą zmianą, niektóre z elementów zostaną wyrenderowane wraz z znacznikiem ✔.

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>Lista rzeczy do spakowania Sally Ride</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Skafander kosmiczny" 
        />
        <Item 
          isPacked={true} 
          name="Hełm ze złotym liściem" 
        />
        <Item 
          isPacked={false} 
          name="Zdjęcie Tam" 
        />
      </ul>
    </section>
  );
}

Spróbuj edytować kod i sprawdź, co zostanie zwrócone w obu przypadkach oraz jak zmieni się wynik!

Zwróć uwagę, jak tworzysz logikę rozgałęzień za pomocą javascriptowych instrukcji if oraz return. W Reakcie kontrola przepływu (taka jak warunki) jest obsługiwana przez JavaScript.

Warunkowe zwracanie niczego z użyciem null

W pewnych sytuacjach nie będziesz chcieć niczego renderować. Dla przykładu, załóżmy, że w ogóle nie chcesz wyświetlać spakowanych przedmiotów. Komponent jednak musi coś zwrócić. W takim przypadku możesz zwrócić null.

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

Jeśli isPacked ma wartość true, komponent nic nie zwróci - null. W przeciwnym razie zwróci JSX do wyrenderowania.

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

export default function PackingList() {
  return (
    <section>
      <h1>Lista rzeczy do spakowania Sally Ride</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Skafander kosmiczny" 
        />
        <Item 
          isPacked={true} 
          name="Hełm ze złotym liściem" 
        />
        <Item 
          isPacked={false} 
          name="Zdjęcie Tam" 
        />
      </ul>
    </section>
  );
}

W praktyce, zwykle komponenty nie zwracają null, ponieważ może to okazać się zaskakujące dla dewelopera, który próbuje wyrenderować dany komponent. Częściej zdarza się, że warunkowo wyświetlamy bądź nie komponent w kodzie JSX-owym rodzica. Oto jak to zrobić!

Warunkowe wyświetlanie JSX-a

W poprzednim przykładzie nasz kod decydował, które (jeśli którekolwiek) drzewo JSX-owe zostanie zwrócone przez komponent. Być może widzisz pewne powtórzenia w wyniku renderowania:

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

jest bardzo podobne do:

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

Oba warunkowe rozgałęzienia zwracają <li className="item">...</li>:

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

W tym przypadku powielenia nie są szkodliwe, jednak mogą one utrudniać utrzymanie kodu. Co w sytuacji, gdybyśmy chcieli zmienić className? Wówczas musielibyśmy to zrobić w dwóch miejscach w kodzie. W takich sytuacjach można warunkowo dołączyć JSX, aby kod był bardziej DRY.

Operator warunkowy (? :)

JavaScript posiada zwartą składnię do tworzenia wyrażenia warunkowego — operator warunkowy, zwany także “operatorem ternarnym” (trójargumentowym).

Zamiast poniższego kodu:

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

Możesz napisać w ten sposób:

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

Możesz to wyrażenie przeczytać jako: “jeśli isPacked ma wartość true, wtedy (?) wyrenderuj name + ' ✔', w przeciwnym razie (:) wyrenderuj name.“)

Dla dociekliwych

Czy te dwa przykłady są w pełni równoważne?

Jeśli wywodzisz się z programowania obiektowego, możesz założyć, że dwa powyższe przykłady są nieco inne, ponieważ jeden z nich może tworzyć dwie różne “instancje” <li>. Jednak elementy JSX nie są “instancjami”, ponieważ nie przechowują żadnego stanu wewnętrznego oraz nie są prawdziwymi węzłami DOM. Tak więc te dwa przykłady w pełni równoważne. Rozdział pt. Zachowywanie i resetowanie stanu zawiera szczegółowe informacje o tym, jak to działa.

Załóżmy, że mamy zadanie umieścić tekst ukończonego elementu w innym znaczniku HTML, na przykład <del>, aby uzyskać efekt przekreślenia. Możesz dodać więcej nowych linii i nawiasów, aby było łatwiej zagnieżdżać więcej JSX w każdym z przypadków:

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

export default function PackingList() {
  return (
    <section>
      <h1>Lista rzeczy do spakowania Sally Ride</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Skafander kosmiczny" 
        />
        <Item 
          isPacked={true} 
          name="Hełm ze złotym liściem" 
        />
        <Item 
          isPacked={false} 
          name="Zdjęcie Tam" 
        />
      </ul>
    </section>
  );
}

Ten sposób sprawdza się przy prostych warunkach, używaj go jednak z umiarem. Jeśli twój komponent robi się nieczytelny, ponieważ posiada zbyt dużą liczbę warunków, rozważ wyodrębnienie komponentów podrzędnych, aby go uporządkować. W Reakcie znaczniki są częścią twojego kodu, więc możesz używać narzędzi takich jak zmienne oraz funkcje do porządkowania złożonych wyrażeń.

Operator logiczny AND (&&)

Kolejnym powszechnie stosowanym skrótem, z którym możesz się zetknąć, jest javascriptowy operator logiczny AND (&&). Wewnątrz komponentów reactowych często wykorzystujemy go, gdy chcemy wyrenderować JSX przy spełnieniu warunku lub gdy nie chcemy nic renderować przy niespełnionym warunku. Przy pomocy operatora && możesz warunkowo wyrenderować “ptaszek” (✔) tylko wtedy, kiedy właściwość isPacked jest ustawiona na true.

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

Możesz to wyrażenie przeczytać jako: “jeśli isPacked, wtedy (&&) wyrenderuj “ptaszek” ✔; w przeciwnym razie nic nie renderuj.”

Poniżej przedstawiono przykład:

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

export default function PackingList() {
  return (
    <section>
      <h1>Lista rzeczy do spakowania Sally Ride</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Skafander kosmiczny" 
        />
        <Item 
          isPacked={true} 
          name="Hełm ze złotym liściem" 
        />
        <Item 
          isPacked={false} 
          name="Zdjęcie Tam" 
        />
      </ul>
    </section>
  );
}

Wyrażenie && w JavaScripcie zwraca wartość z prawej strony operatora (w naszym przypadku “ptaszek” ✔), jeśli po lewej stronie warunek został spełniony (ma wartość true). Jeśli jednak warunek ma wartość false, całe wyrażenie staje się false i nie zostaje spełnione. React traktuje false jako “dziurę” w drzewie JSX, podobnie jak null czy undefined i nie renderuje niczego w tym miejscu.

Zwróć uwagę

Nie umieszczaj liczb po lewej stronie znacznika &&.

Aby sprawdzić warunek, JavaScript automatycznie konwertuje lewą stronę na wartość logiczną. Jeśli jednak lewa strona wyrażenia ma wartość 0, całe wyrażenie otrzyma tę wartość (0), a React z radością wyrenderuje 0, zamiast niczego nie renderować.

Na przykład, powszechnym błędem jest pisanie kodu messageCount && <p>New messages</p>. Łatwo założyć, że nic nie zostanie wyrenderowane, kiedy messageCount ma wartość 0, jednak tak naprawdę wyrenderowane zostanie samo 0!

Aby to naprawić, zastosuj wartość logiczną po lewej stronie: messageCount > 0 && <p>New messages</p>.

Warunkowe przypisywanie JSX-a do zmiennej

Jeśli skróty przeszkadzają w pisaniu zwykłego kodu, spróbuj użyć warunku if oraz zmiennej. Możesz ponownie przypisać wartości do zmiennej, zdefiniowanej za pomocą let, zacznij więc od podania domyślnej wartości, którą chcesz wyświetlić:

let itemContent = name;

Użyj warunku if, aby przypisać ponownie wyrażenie JSX-owe do itemContent, jeśli isPacked posiada wartość true:

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

Używanie nawiasów klamrowych otwiera “okno na świat JavaScriptu”. Umieść zmienną wewnątrz nawiasów klamrowych w zwróconym drzewie JSX, zagnieżdżając uprzednio przeliczone wyrażenie wewnątrz JSX:

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

Ten sposób jest najbardziej rozwlekły, jednocześnie jednak najbardziej elastyczny. Poniżej przedstawiono przykład:

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

export default function PackingList() {
  return (
    <section>
      <h1>Lista rzeczy do spakowania Sally Ride</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Skafander kosmiczny" 
        />
        <Item 
          isPacked={true} 
          name="Hełm ze złotym liściem" 
        />
        <Item 
          isPacked={false} 
          name="Zdjęcie Tam" 
        />
      </ul>
    </section>
  );
}

Tak jak poprzednio, ten sposób działa nie tylko dla tekstu, ale także dla dowolnego kodu 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>Lista rzeczy do spakowania Sally Ride</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Skafander kosmiczny" 
        />
        <Item 
          isPacked={true} 
          name="Hełm ze złotym liściem" 
        />
        <Item 
          isPacked={false} 
          name="Zdjęcie Tam" 
        />
      </ul>
    </section>
  );
}

Jeśli znasz dobrze JavaScriptu, ta różnorodność sposobów może początkowo wydawać się przytłaczająca. Jednak ich nauka pomoże ci czytać i pisać dowolny kod javascriptowy — nie tylko komponenty reactowe! Na początku wybierz jeden preferowany sposób, a następnie zapoznaj się ponownie z tymi notatkami, jeśli zapomnisz zasady działania pozostałych.

Powtórka

  • W Reakcie kontrolujesz logikę rozgałęzień za pomocą JavaScriptu.
  • Możesz zwrócić wyrażenie JSX-owe warunkowo, używając do tego instrukcji if.
  • Możesz warunkowo zapisać część kodu JSX w zmiennej, a następnie dołączyć go do innego kodu JSX, używając nawiasów klamrowych.
  • W JSX {warunek ? <A /> : <B />} oznacza: “jeśli warunek jest prawdziwy, wyrenderuj <A />, w przeciwnym razie wyrenderuj <B />.
  • W JSX {warunek && <A />} oznacza: “jeśli warunek jest prawdziwy, wyrenderuj <A />, w przeciwnym razie nic nie renderuj”.
  • Skrótowy zapis jest dość powszechny, ale nie musisz go używać, jeśli wolisz zwykłe if.

Wyzwanie 1 z 3:
Wyświetl znacznik dla niespakowanych przedmiotów za pomocą ? :

Użyj operatora warunkowego (warunek ? a : b), aby wyświetlić ❌, jeśli isPacked nie ma wartości true.

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

export default function PackingList() {
  return (
    <section>
      <h1>Lista rzeczy do spakowania Sally Ride</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Skafander kosmiczny" 
        />
        <Item 
          isPacked={true} 
          name="Hełm ze złotym liściem" 
        />
        <Item 
          isPacked={false} 
          name="Zdjęcie Tam" 
        />
      </ul>
    </section>
  );
}