React

Suspense: cosa sospende e cosa no

Suspense mostra un fallback mentre un componente attende una promessa: funziona con lazy e use, non con una fetch avviata dentro useEffect.

In sintesi

  • Suspense intercetta una promessa lanciata durante il render: senza quella promessa non mostra niente.
  • Una fetch avviata in useEffect non sospende: il componente renderizza lo stato di caricamento che scrivi tu.
  • Il fallback sostituisce l'intero sottoalbero, quindi i boundary annidati limitano il salto.

Suspense sospende solo un componente che lancia una promessa durante il render: React mostra il fallback e riprova quando la promessa si risolve. Una fetch avviata dentro useEffect non sospende nulla.

Cosa sospende davvero

Tre casi entrano nel meccanismo: lazy() che carica un modulo, use(promise) di React 19 che legge una promessa già creata, e le librerie dati che lanciano la promessa al posto tuo. Tutto il resto resta stato normale.

Un caso eseguibile

import { Suspense, lazy } from "react";

const Pannello = lazy(() => import("./Pannello"));

export function Scheda({ aperta }) {
  if (!aperta) return null;
  return (
    Caricamento}>
      
    
  );
}

Il file gira in un progetto Vite con React 19: Suspense avvolge il componente pigro e il fallback appare finché il modulo non arriva. Il resto della pagina resta interattivo.

Skeleton o testo

Il fallback è interfaccia: uno skeleton che conserva l'altezza evita il salto di layout, un testo breve costa meno da leggere. In entrambi i casi il contenuto deve avere dimensioni stabili, altrimenti il Cumulative Layout Shift peggiora proprio dove volevi migliorare.

La categoria skeleton raccoglie i segnaposto del catalogo, con uno skeleton di blocco già pronto; per un'attesa breve c'è lo spinner di Kibo UI, licenza MIT.

La limitazione

Suspense non scarica dati da solo e non riprova una promessa rifiutata: un errore dentro il sottoalbero sospeso richiede un error boundary, altrimenti la pagina resta sul fallback. Non esiste un timeout configurabile, quindi non puoi dire a React di aspettare al massimo duecento millisecondi.

Dove continuare

Lo streaming con Suspense è in streaming e Suspense in Next.js; il modello dei server component è in guida ai server component; le novità della versione sono in React 19, cosa cambia. Il confronto fra i due framework più diffusi è in Vue 3 vs React.

Domande frequenti

Suspense funziona con una fetch in useEffect?

No. Una fetch avviata in useEffect non lancia promesse durante il render, quindi Suspense non la vede e mostra lo stato di caricamento che hai scritto.

Serve React 19 per usare Suspense?

No per lazy, sì per use. Suspense esiste dalla 16.6 e carica componenti pigri; la lettura di una promessa con use richiede React 19.

Che differenza c'è fra Suspense e un if di caricamento?

Il controllo sta dove nasce la promessa. Un if dipende da uno stato che aggiorni tu; Suspense dipende da un render che lancia la promessa.

Posso mettere Suspense dentro una lista?

Sì, ma un boundary per riga produce molti fallback. Conviene un boundary intorno alla lista e skeleton di riga dentro il fallback.

Suspense sostituisce un error boundary?

No. Suspense gestisce l'attesa e l'error boundary gestisce l'errore: servono entrambi, con il boundary sopra il Suspense.