Renderizzazione Condizionale

I tuoi componenti dovranno spesso mostrare cose differenti a seconda di diverse condizioni. In React, puoi renderizzare condizionalmente JSX usando la sintassi JavaScript con istruzioni come if, && e gli operatori ? :.

Imparerai

  • Come ritornare JSX differenti a seconda di una condizione
  • Come includere o escludere condizionalmente una porzione di JSX
  • Comuni scorciatoie di sintassi condizionale che incontrerai nele basi di codice React

Ritornare JSX condizionalmente

Immagina di avere un componente PackingList che renderizza diversi Item, i quali possono essere marcati come imballati o meno:

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>
  );
}

Nota che alcuni componenti Item hanno la loro prop isPacked settata a true invece che false. Vuoi aggiungere un segno di spunta (✔) agli elementi imballati se isPacked={true}.

Puoi scrivere questo come un’istruzione if/else in questo modo:

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

Se la prop isPacked è true, questo codice ritorna un albero JSX differente. Con questo cambiamento, alcuni elementi ottengono un segno di spunta alla fine:

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>
  );
}

Prova a modificare cosa viene ritornato in entrambi i casi e guarda come cambia il risultato!

Nota come stai creando una logica a diramazione con le istruzioni if e return di JavaScript. In React, il flusso di controllo (come le condizioni) è gestito da JavaScript.

Non restituire nulla condizionalmente con null

In alcune situazioni, non vorrai renderizzare nulla. Per esempio, diciamo che non vuoi mostrare gli elementi imballati. Un componente deve ritornare qualcosa. In questo caso, puoi ritornare null:

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

Se isPacked è true, il componente non renderizzerà nulla, ovvero null. Altrimenti, ritornerà il JSX da renderizzare.

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>
  );
}

Nella pratica, ritornare null da un componente non è comune perché potrebbe sorprendere un developer che sta cercando di renderizzarlo. Più spesso, condizionerai l’inclusione o l’esclusione del componente nel JSX del componente genitore. Ecco qui come fare!

Includere JSX condizionalmente

Nell’esempio precedente, hai controllato quale albero JSX sarebbe stato ritornato dal componente (se presente!). Potresti aver già notato qualche duplicazione nell’output renderizzato:

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

è molto simile a

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

Entrambi i rami condizionali ritornano <li className="item">...</li>:

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

Anche se questa duplicazione non è dannosa, potrebbe rendere il tuo codice più difficile da mantenere. Cosa succederebbe se volessi cambiare la className? Dovresti farlo in due posti nel tuo codice! In una situazione del genere, potresti includere condizionalmente un po’ di JSX per rendere il tuo codice più DRY.

Operatore (ternario) condizionale (? :)

JavaScript ha una sintassi compatta per scrivere un’espressione condizionale — l’operatore condizionale o “operatore ternario”.

Invece di questo:

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

Puoi scrivere questo:

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

Puoi leggerlo come “se isPacked è true, allora (?) renderizza name + ' ✔', altrimenti (:) renderizza name.

Approfondimento

Questi due esempi sono equivalenti?

Se hai un background di programmazione orientata agli oggetti, potresti supporre che i due esempi sopra siano leggermente diversi perché uno di essi potrebbe creare due “istanze” diverse di <li>. Ma gli elementi JSX non sono “istanze” perché non mantengono alcuno stato interno e non sono nodi del DOM reali. Sono descrizioni leggere, come i progetti. Quindi questi due esempi, infatti, sono completamente equivalenti. Preservare e Resettare lo Stato entra nel dettaglio su come funziona questo.

Ora immagina di voler racchiudere il testo dell’elemento completato in un altro tag HTML, come <del> per barrarlo. Puoi aggiungere ancora più righe e parentesi cosí che sia più semplice annidare più JSX in ciascuno dei casi:

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>
  );
}

Questo stile funziona bene per condizioni semplici, ma utilizzalo con moderazione. Se i tuoi componenti diventano disordinati con troppi markup condizionali nidificati, considera di estrarre i componenti figli per riordinare le cose. In React, il markup fa parte del tuo codice, quindi puoi usare strumenti come le variabili e le funzioni per ripulire le espressioni complesse.

Operatore logico AND (&&)

Un’altra scorciatoia comune che incontrerai è l’operatore logico AND (&&). All’interno dei componenti React, si presenta spesso quando si desidera renderizzare un po’ di JSX quando la condizione è vera, o altrimenti non si renderizza nulla. Con &&, potresti renderizzare condizionalmente il segno di spunta solo se isPacked è true:

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

Puoi leggere questo come “se isPacked è true, allora (&&) renderizza il segno di spunta, altrimenti, non renderizzare nulla”.

Eccolo in azione:

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>
  );
}

Una espressione JavaScript && restituisce il valore del suo lato destro (nel nostro caso, il segno di spunta) se il lato sinistro (la nostra condizione) è true. Ma se la condizione è false, l’intera espressione diventa false. React considera false come un “buco” nell’albero JSX, proprio come null o undefined e non renderizza nulla al suo posto.

Insidia

Non mettere i numeri sul lato sinistro di &&.

Per testare le condizioni, JavaScript converte automaticamente il lato sinistro in un booleano. Tuttavia, se il lato sinistro è 0, l’intera espressione ottiene quel valore (0) e React renderizzerà volentieri 0 anziché nulla.

Per esempio, un errore comune è scrivere codice come messageCount && <p>New messages</p>. È facile presumere che non renderizzi nulla quando messageCount è 0, ma in realtà renderizza il 0 stesso!

Per risolvere il problema, rendi il lato sinistro un booleano: messageCount > 0 && <p>New messages</p>.

Assegnare condizionalmente JSX ad una variabile

Quando introduci le scorciatoie nella scrittura di codice semplice, prova ad usare un’istruzione if ed una variabile. Puoi riassegnare le variabili definite con let, quindi inizia fornendo il contenuto predefinito che vuoi visualizzare, il nome:

let itemContent = name;

Utilizza un’istruzione if per riassegnare un’espressione JSX ad itemContent se isPacked è true:

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

Le parentesi graffe aprono una “finestra nel mondo JavaScript”. Inserisci la variabile con le parentesi graffe nell’albero JSX restituito, annidando l’espressione precedentemente calcolata all’interno del JSX:

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

Questo stile è più verboso, ma è anche più flessibile. Ecco come funziona:

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>
  );
}

Come prima, questo funziona non solo per il testo, ma anche per il JSX arbitrario:

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>
  );
}

Se non hai familiarità con JavaScript, questa varietà di stili potrebbe sembrarti travolgente all’inizio. Tuttavia, impararli ti aiuterà a leggere e scrivere qualsiasi codice JavaScript - e non solo i componenti React! Scegli quello che preferisci per iniziare e poi consulta di nuovo questo riferimento se dimentichi come funzionano gli altri.

Riepilogo

  • In React, controlli la logica di ramificazione con JavaScript.
  • Puoi ritornare condizionalmente un’espressione JSX con un’istruzione if.
  • Puoi salvare condizionalmente un’espressione JSX in una variabile e quindi includerla in altri JSX utilizzando le parentesi graffe.
  • Nella sintassi JSX, {cond ? <A /> : <B />}, significa se cond è true, renderizza <A />, altrimenti <B />.
  • Nella sintassi JSX, {cond && <A />} significa se cond è true, renderizza <A />, altrimenti nulla.
  • Le scorciaotie sono comuni, ma non sei costretto ad utilizzarle se preferisci un semplice if.

Sfida 1 di 3:
Mostra un’icona per gli oggetti incompleti con ? :

Usa l’operatore condizionale (cond ? a : b) per renderizzare una ❌ se isPacked non è true.

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>
  );
}