# Riprovare dopo un errore di Suspense

Suspense non ha un pulsante di retry: si riprova rimontando il confine con una key nuova e invalidando la cache che ha lanciato la promise.

> Pagina: https://ui.eneawork.it/blog/react-suspense-retry
> Markdown: https://ui.eneawork.it/blog/react-suspense-retry.md

*2026-11-01*

Suspense non offre un retry: per riprovare si rimonta il confine con una key nuova e si invalida la cache che ha lanciato la promise. Senza i due passaggi il confine rilegge lo stesso rifiuto e resta sull’errore.

Il catalogo EneUI conta 111.985 componenti, 1.556 blocchi e 12.808 icone da 1.472 librerie, misurati da /api/stats il 1 novembre 2026. La cifra viene da una query all’endpoint, non da una stima: conta i record pubblicati e non dice quanti usino questo pattern correttamente.

## Chi cattura cosa

Suspense intercetta una promise lanciata durante il render e mostra il fallback finché non si risolve. Un errore, compresa una promise rifiutata letta da use(), non passa da Suspense: va all’error boundary più vicino. Per questo un retry completo ha bisogno di entrambi i confini.

## Lo schema con la key

Il contatore di tentativi vive sopra l’error boundary e diventa la key del confine stesso: cambiare la key equivale a costruire un confine nuovo.

function Panel({ id }) { const [attempt, setAttempt] = useState(0); return ( Load failed{" "} setAttempt(attempt + 1)}>Try again } > Loading}> ); }

## Perché la key basta per lo stato

React tratta una key diversa come un componente diverso: smonta il sottoalbero, scarta lo stato dell’error boundary e riparte con il render iniziale. Anche la promise pendente sparisce con il sottoalbero, quindi il nuovo tentativo parte da zero.

## La cache resta

Se il livello dati conserva la promise rifiutata, il rimontaggio la ritrova e rilancia lo stesso errore. Prima di incrementare il tentativo va tolta la voce, altrimenti il pulsante sembra non fare niente.

async function retry() { await cache.delete(`details:${id}`); setAttempt((n) => n + 1); }

L’ordine conta: la cancellazione attende, poi il contatore cambia. Se si inverte, il nuovo confine può leggere la voce vecchia prima che sparisca.

## Il comando

Il pacchetto react-error-boundary offre resetKeys e onReset, così il contatore diventa la chiave di reset senza scrivere un boundary a mano.

npm install react-error-boundary npm ls react-error-boundary

## Record vivi nel catalogo

Tre record che mostrano uno stato di caricamento prima dei dati: leads-data-table riempie una tabella da una fonte remota, project-data-table filtra righe arrivate dopo, area-chart disegna solo quando la serie è pronta. Sono record fra i 111.985 componenti del catalogo.

## Fonte e licenza

React è distribuito con licenza MIT e react-error-boundary con licenza MIT. La documentazione React su Suspense descrive il fallback e quella sugli error boundary il recupero: le due pagine vanno lette insieme, perché il retry vive nell’intersezione.

## La limitazione

Il retry per rimontaggio perde lo stato locale del sottoalbero, la posizione di scroll e il focus. Un retry automatico su un errore 500 moltiplica le richieste, quindi il numero di tentativi va limitato e il pulsante manuale resta la scelta predefinita.

## Dove continuare

Le basi sono in Suspense; il confine che cattura gli errori è in error boundary pattern; il confronto con lo streaming di Next.js è in streaming e Suspense in Next.js.

## FAQ

### Perché Suspense non ha un retry integrato?

Perché non sa chi ha lanciato la promise né come invalidarla. Il retry appartiene al livello dati, che conosce la chiave della cache, e al confine, che può rimontare.

### Serve una key nuova o basta un setState?

Serve una key nuova sul confine, oppure resetKeys se usi react-error-boundary. Un setState nello stesso confine non cancella lo stato di errore.

### Il retry funziona senza error boundary?

No: una promise rifiutata lancia un errore che senza boundary risale fino alla radice e smonta l’app. Il boundary è la condizione per mostrare un pulsante invece di una pagina bianca.

### Posso fare retry automatico?

Sì, con un effetto che incrementa il tentativo dopo un ritardo, ma va limitato: senza tetto un errore 500 produce una raffica di richieste e consuma quota.

### Cosa succede allo stato del componente rimontato?

Si perde. Il rimontaggio è un componente nuovo, quindi stato locale, scroll e focus tornano ai valori iniziali: se vanno conservati, teneteli sopra il confine.
