00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Rendering Condizionale e Liste

Rendering Condizionale

In React, il rendering condizionale funziona come le condizioni in JavaScript. Puoi usare if, operatore ternario, && logico e switch per decidere cosa mostrare.

if/else con Return Anticipato

L’approccio più diretto: usa if per restituire JSX diverso in base alla condizione.

function SaluoUtente({ isLoggato, nome }) {
  if (!isLoggato) {
    return <p>Effettua il login per continuare.</p>;
  }

  return <h1>Benvenuto, {nome}!</h1>;
}

Il pattern del return anticipato (early return) è particolarmente utile per gestire stati di caricamento, errori e casi limite.

function DettaglioProdotto({ prodotto, caricamento, errore }) {
  if (caricamento) {
    return <Spinner />;
  }

  if (errore) {
    return <MessaggioErrore messaggio={errore} />;
  }

  if (!prodotto) {
    return <p>Prodotto non trovato.</p>;
  }

  return (
    <div>
      <h1>{prodotto.nome}</h1>
      <p>{prodotto.descrizione}</p>
      <span>{prodotto.prezzo} EUR</span>
    </div>
  );
}

Operatore Ternario

L’operatore ternario (condizione ? veroJSX : falsoJSX) è perfetto per scegliere tra due alternative direttamente nel JSX.

function StatoOrdine({ stato }) {
  return (
    <div>
      <h2>Il tuo ordine</h2>
      {stato === "completato" ? (
        <p className="successo">Ordine completato con successo!</p>
      ) : (
        <p className="in-corso">Ordine in elaborazione...</p>
      )}
    </div>
  );
}

Ternari Annidati

I ternari annidati riducono la leggibilità. Evitali quando possibile.

// SCONSIGLIATO: ternari annidati
function Badge({ ruolo }) {
  return (
    <span>
      {ruolo === "admin"
        ? "Amministratore"
        : ruolo === "editor"
        ? "Editore"
        : ruolo === "viewer"
        ? "Lettore"
        : "Ospite"}
    </span>
  );
}

// MEGLIO: estrai la logica in una funzione o usa una mappa
function Badge({ ruolo }) {
  const etichette = {
    admin: "Amministratore",
    editor: "Editore",
    viewer: "Lettore",
  };

  return <span>{etichette[ruolo] ?? "Ospite"}</span>;
}

Operatore && (AND Logico)

L’operatore && è utile quando vuoi mostrare qualcosa oppure nulla.

function Notifiche({ messaggi, mostraConteggio }) {
  return (
    <div>
      <h2>Notifiche</h2>

      {messaggi.length > 0 && (
        <ul>
          {messaggi.map((msg) => (
            <li key={msg.id}>{msg.testo}</li>
          ))}
        </ul>
      )}

      {mostraConteggio && (
        <p>Totale: {messaggi.length}</p>
      )}

      {messaggi.length === 0 && (
        <p>Nessuna notifica.</p>
      )}
    </div>
  );
}

Attenzione al Falsy con &&

Un errore comune: il valore 0 viene renderizzato da React, a differenza di false, null e undefined.

function ListaArticoli({ articoli }) {
  return (
    <div>
      {/* BUG: se articoli.length è 0, renderizza "0" */}
      {articoli.length && <Lista articoli={articoli} />}

      {/* CORRETTO: converti a booleano */}
      {articoli.length > 0 && <Lista articoli={articoli} />}

      {/* CORRETTO: doppia negazione */}
      {!!articoli.length && <Lista articoli={articoli} />}
    </div>
  );
}

Switch/Istruzioni Complesse

Per condizioni con molte opzioni, estrai la logica in una funzione separata.

function IconaStato({ stato }) {
  const renderIcona = () => {
    switch (stato) {
      case "successo":
        return <IconaCheck className="verde" />;
      case "errore":
        return <IconaCroce className="rosso" />;
      case "caricamento":
        return <Spinner />;
      case "avviso":
        return <IconaAvviso className="giallo" />;
      default:
        return <IconaInfo className="blu" />;
    }
  };

  return <div className="icona-stato">{renderIcona()}</div>;
}

Pattern Mappa di Componenti

const COMPONENTI_PASSO = {
  1: DatiPersonali,
  2: Indirizzo,
  3: Pagamento,
  4: Riepilogo,
};

function Wizard({ passoCorrente }) {
  const Componente = COMPONENTI_PASSO[passoCorrente];

  if (!Componente) return <p>Passo non valido</p>;

  return <Componente />;
}

Rendering di Liste

map() per Renderizzare Liste

Il metodo map() è il modo standard per trasformare un array di dati in un array di elementi React.

function ListaFrutti() {
  const frutti = ["Mela", "Banana", "Arancia", "Kiwi", "Pera"];

  return (
    <ul>
      {frutti.map((frutto) => (
        <li key={frutto}>{frutto}</li>
      ))}
    </ul>
  );
}

Liste con Oggetti

interface Utente {
  id: number;
  nome: string;
  email: string;
  attivo: boolean;
}

function ListaUtenti({ utenti }: { utenti: Utente[] }) {
  return (
    <div className="lista-utenti">
      {utenti.map((utente) => (
        <div key={utente.id} className="utente-card">
          <h3>{utente.nome}</h3>
          <p>{utente.email}</p>
          <span className={utente.attivo ? "badge-attivo" : "badge-inattivo"}>
            {utente.attivo ? "Attivo" : "Inattivo"}
          </span>
        </div>
      ))}
    </div>
  );
}

Estrarre il Componente della Lista

Per liste complesse, estrai l’elemento in un componente separato.

function CardProdotto({ prodotto }) {
  return (
    <div className="card-prodotto">
      <img src={prodotto.immagine} alt={prodotto.nome} />
      <h3>{prodotto.nome}</h3>
      <p>{prodotto.descrizione}</p>
      <span className="prezzo">{prodotto.prezzo.toFixed(2)} EUR</span>
    </div>
  );
}

function GrigliaProdotti({ prodotti }) {
  if (prodotti.length === 0) {
    return <p>Nessun prodotto disponibile.</p>;
  }

  return (
    <div className="griglia">
      {prodotti.map((prodotto) => (
        <CardProdotto key={prodotto.id} prodotto={prodotto} />
      ))}
    </div>
  );
}

La Prop key

La prop key è fondamentale per le liste in React. Aiuta React a identificare quali elementi sono cambiati, aggiunti o rimossi, ottimizzando il re-rendering.

Regole per le Key

// CORRETTO: usa un ID unico e stabile
{utenti.map(utente => (
  <Utente key={utente.id} {...utente} />
))}

// CORRETTO: stringa unica
{categorie.map(cat => (
  <Categoria key={cat.slug} nome={cat.nome} />
))}

// SCONSIGLIATO: indice dell'array (causa problemi con riordinamenti)
{utenti.map((utente, index) => (
  <Utente key={index} {...utente} />
))}

// ERRORE: chiave duplicata
{/* Se due utenti hanno lo stesso nome, React si confonde */}
{utenti.map(utente => (
  <Utente key={utente.nome} {...utente} />
))}

Quando l’Indice è Accettabile come Key

L’indice è accettabile solo se tutte queste condizioni sono vere:

  1. La lista è statica (non viene mai riordinata o filtrata)
  2. Gli elementi non hanno un ID unico
  3. La lista non viene mai modificata (nessuna aggiunta o rimozione)

Problemi con Key Errate

// BUG: usando l'indice come key con una lista dinamica
function ListaTask() {
  const [tasks, setTasks] = useState([
    { id: 1, testo: "Comprare latte" },
    { id: 2, testo: "Studiare React" },
    { id: 3, testo: "Fare esercizio" },
  ]);

  const rimuoviPrimo = () => {
    setTasks(tasks.slice(1));
  };

  return (
    <div>
      <button onClick={rimuoviPrimo}>Rimuovi primo</button>
      {tasks.map((task, index) => (
        // Con key={index}, React confonde gli elementi dopo la rimozione
        // Con key={task.id}, React sa esattamente quale rimuovere
        <input key={task.id} defaultValue={task.testo} />
      ))}
    </div>
  );
}

Liste Filtrate e Ordinate

Filtrare Prima di Renderizzare

function ListaProdotti({ prodotti, categoriaFiltro, ordinamento }) {
  // Filtra
  const prodottiFiltrati = prodotti.filter((p) => {
    if (!categoriaFiltro) return true;
    return p.categoria === categoriaFiltro;
  });

  // Ordina
  const prodottiOrdinati = [...prodottiFiltrati].sort((a, b) => {
    switch (ordinamento) {
      case "prezzo-asc":
        return a.prezzo - b.prezzo;
      case "prezzo-desc":
        return b.prezzo - a.prezzo;
      case "nome":
        return a.nome.localeCompare(b.nome);
      default:
        return 0;
    }
  });

  return (
    <div>
      <p>Mostrando {prodottiOrdinati.length} di {prodotti.length} prodotti</p>
      <div className="griglia">
        {prodottiOrdinati.map((p) => (
          <CardProdotto key={p.id} prodotto={p} />
        ))}
      </div>
    </div>
  );
}

Raggruppare Elementi

function ListaContatti({ contatti }) {
  // Raggruppa per lettera iniziale
  const gruppati = contatti.reduce((acc, contatto) => {
    const lettera = contatto.nome[0].toUpperCase();
    if (!acc[lettera]) acc[lettera] = [];
    acc[lettera].push(contatto);
    return acc;
  }, {});

  return (
    <div>
      {Object.entries(gruppati)
        .sort(([a], [b]) => a.localeCompare(b))
        .map(([lettera, gruppo]) => (
          <div key={lettera}>
            <h2 className="lettera-gruppo">{lettera}</h2>
            <ul>
              {gruppo.map((contatto) => (
                <li key={contatto.id}>{contatto.nome}</li>
              ))}
            </ul>
          </div>
        ))}
    </div>
  );
}

Rendering di Liste Vuote

Gestisci sempre il caso di lista vuota per una buona esperienza utente.

function ListaRisultati({ risultati, termineRicerca }) {
  if (risultati.length === 0) {
    return (
      <div className="stato-vuoto">
        <img src="/empty-state.svg" alt="" />
        <h3>Nessun risultato trovato</h3>
        <p>
          La ricerca per "{termineRicerca}" non ha prodotto risultati.
          Prova con termini diversi.
        </p>
      </div>
    );
  }

  return (
    <ul>
      {risultati.map((r) => (
        <li key={r.id}>{r.titolo}</li>
      ))}
    </ul>
  );
}

Best Practices

  • Usa il return anticipato per gestire loading, errori e stati vuoti
  • Evita ternari annidati: estrai la logica in funzioni o mappe
  • Attenzione al falsy con &&: usa sempre confronti espliciti (> 0, !== null)
  • Usa sempre key uniche e stabili nelle liste: preferisci ID dal database o UUID
  • Non usare l’indice come key in liste dinamiche
  • Filtra e ordina prima di map(): non mischiare logica e rendering
  • Gestisci sempre lo stato vuoto delle liste

Il rendering condizionale e la gestione delle liste sono operazioni quotidiane in React. Scegli il pattern condizionale più leggibile per ogni situazione, usa map() per le liste con key stabili, e gestisci sempre i casi limite come caricamento, errori e liste vuote. Questi pattern formano la base per costruire interfacce dinamiche e robuste.