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.
Record vivi nel catalogo
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.