Un error boundary è un componente React che intercetta gli errori generati durante il rendering dei componenti al suo interno e mostra una UI di fallback invece di far crollare l'intera app. Deve essere un class component che definisce static getDerivedStateFromError, perché non esiste un hook per farlo. Lo scrivi una volta e lo metti attorno a qualsiasi parte dell'albero.
Premi "Break the profile" per far generare un errore al figlio durante il rendering.
Il profilo viene sostituito dal fallback, e il resto della pagina continua a funzionare. La console mostra l'errore due volte: React registra ogni errore intercettato con console.error, e componentDidCatch lo registra di nuovo. "Try again" elimina la causa (broken) e l'errore del confine, quindi il profilo si renderizza di nuovo. Togli this.props.onReset(); da reset e Try again ricade subito nel fallback, perché nulla ha sistemato la causa.
Come funziona la classe
Due metodi rendono una classe un error boundary:
static getDerivedStateFromError(error)viene eseguito durante il rendering, subito dopo che un figlio ha generato un errore. Restituisce l'aggiornamento di stato che fa passare il confine al suo fallback. Deve essere puro: niente log, niente richieste.componentDidCatch(error, info)viene eseguito dopo che il fallback è sullo schermo. Usalo per gli effetti collaterali come inviare l'errore a un servizio di segnalazione.info.componentStackelenca il componente che ha generato l'errore e quelli sopra di esso.
class ErrorBoundary extends Component {
state = { error: null };
static getDerivedStateFromError(error) {
return { error }; // switch to the fallback
}
componentDidCatch(error, info) {
reportError(error, info.componentStack); // your logging service
}
render() {
if (this.state.error) return this.props.fallback;
return this.props.children;
}
}
Non esiste un equivalente con gli hook, quindi anche un'app scritta solo con function component ha bisogno di questa unica classe. La pagina sui class component spiega la sintassi delle classi se ti è nuova.
Cosa intercetta un confine, e cosa no
Un confine intercetta gli errori che avvengono mentre React lavora sui componenti al suo interno:
- il rendering (il corpo di un function component, il
renderdi una classe), - i metodi del ciclo di vita e i costruttori dei class component figli,
- gli effetti (
useEffect,useLayoutEffect) e i ref callback, - una promise rifiutata letta con use e, in React 19, un errore generato da una form action o da una funzione passata allo
startTransitiondiuseTransition.
Non intercetta:
- gli errori nei gestori di eventi,
- il codice asincrono che avvii tu:
setTimeout, le callback.then(), unawaitin un gestore di eventi, - gli errori nel
renderdel confine stesso (li intercetta il confine successivo più in alto), - gli errori durante il rendering lato server.
I gestori di eventi sono esclusi perché non rompono il rendering. Lo schermo è ancora in uno stato valido, quindi basta un try/catch nel gestore. Se invece vuoi che compaia il confine, memorizza l'errore nello stato e generalo al rendering successivo:
Il primo pulsante lascia i pulsanti sullo schermo e stampa solo un errore non intercettato nella console. Il secondo intercetta il rifiuto, lo memorizza, e il confine prende il controllo.
Dove mettere i confini
Un confine attorno all'intera app evita la schermata bianca, ma poi qualsiasi piccolo errore sostituisce tutto. Metti i confini attorno a parti che possono fallire in modo indipendente: un widget nella barra laterale, un grafico, ogni route. Un errore allora costa all'utente un pannello, non la pagina.
Solo il pannello Stocks mostra il suo fallback. Sposta entrambi i widget in un unico <ErrorBoundary> e il pannello Weather, che funziona, sparisce insieme a lui.
Senza alcun confine, React rimuove l'intero albero dallo schermo quando un errore di rendering non viene intercettato. Una pagina vuota è più sicura di una rotta che mostra dati sbagliati, ma gli utenti la leggono come un crash.
La libreria react-error-boundary
Il pacchetto react-error-boundary racchiude la classe per te e aggiunge funzioni per l'azzeramento. Non è disponibile in questo editor, quindi eccolo in un blocco statico:
import { ErrorBoundary, useErrorBoundary } from 'react-error-boundary';
function Fallback({ error, resetErrorBoundary }) {
return (
<div role="alert">
<p>Something went wrong: {error.message}</p>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
);
}
<ErrorBoundary FallbackComponent={Fallback} onReset={() => refetch()} resetKeys={[userId]}>
<Profile userId={userId} />
</ErrorBoundary>;
// Inside a child: hand an async error to the boundary
const { showBoundary } = useErrorBoundary();
fetchData().catch(showBoundary);
resetKeys azzera il confine quando cambia uno qualsiasi dei valori elencati, e showBoundary fa il trucco "memorizza e genera" dell'esempio precedente.
Segnalare gli errori in React 19
React 19 segnala gli errori in un modo nuovo. Gli errori intercettati da un confine vengono registrati una volta con console.error, e quelli non intercettati vanno a window.reportError. Per inviarli al tuo servizio, passa delle opzioni a createRoot. Ogni opzione sostituisce il corrispondente log predefinito:
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'), {
onCaughtError(error, errorInfo) {
// an error boundary caught it
logToService('caught', error, errorInfo.componentStack);
},
onUncaughtError(error, errorInfo) {
// no boundary caught it, and React removed the tree
logToService('uncaught', error, errorInfo.componentStack);
},
onRecoverableError(error, errorInfo) {
// React recovered by itself, for example after a hydration mismatch
logToService('recovered', error, errorInfo.componentStack);
},
});
root.render(<App />);
onRecoverableError è per gli errori che React ha sistemato senza il tuo aiuto, come un hydration mismatch o un errore di rendering sparito quando React ha riprovato. hydrateRoot accetta le stesse tre opzioni.
Errori comuni
Mettere il confine dentro il componente che genera l'errore. Un confine intercetta solo gli errori dei suoi figli. Se Profile renderizza <ErrorBoundary> attorno al proprio JSX e poi genera un errore nel proprio corpo, l'errore lo supera e arriva al confine successivo più in alto. Racchiudi il componente dal suo genitore.
Effetti collaterali in getDerivedStateFromError. Viene eseguito durante il rendering e può essere eseguito più di una volta, quindi limitati a restituire lo stato. I log vanno in componentDidCatch o nell'onCaughtError della root.
Un azzeramento che non sistema nulla. Azzerare l'errore del confine renderizza gli stessi figli con le stesse props. Se generano di nuovo un errore, l'utente torna al fallback. Prima cambia ciò che ha causato l'errore (recupera di nuovo i dati, elimina l'input errato, cambia la key), poi azzera l'errore, come fa il primo esempio con onReset.
Un solo confine per tutta l'app, e nient'altro. Evita la pagina vuota ma trasforma ogni piccolo guasto in un errore a tutta pagina. Aggiungi confini attorno alle funzionalità, e tieni quello al livello più alto come ultima risorsa.
Fallback che ti nascondono l'errore. Un messaggio cortese va bene per gli utenti, ma assicurati che l'errore arrivi comunque ai tuoi log. React 19 per default registra nella console gli errori intercettati; in produzione quella console è dell'utente, quindi invia gli errori a un servizio da componentDidCatch o da onCaughtError.
Gli error boundary si abbinano in modo naturale a <Suspense>: Suspense gestisce il "non ancora pronto", il confine gestisce il "fallito". Metti il confine fuori dal Suspense, come negli esempi con use, così un solo componente copre caricamento, successo e fallimento.
Domande frequenti
Cos'è un error boundary in React?
Un componente che intercetta gli errori JavaScript generati durante il rendering di qualsiasi componente al suo interno, e renderizza invece una UI di fallback. Senza, un errore durante il rendering rimuove l'intera app dallo schermo.
Esiste un hook per gli error boundary?
No. Un error boundary deve essere un class component con static getDerivedStateFromError (e facoltativamente componentDidCatch). Lo scrivi una volta e lo usi dai function component come qualsiasi altro componente, oppure installi react-error-boundary, che racchiude la classe per te.
Gli error boundary intercettano gli errori nei gestori di eventi?
No. I gestori di eventi vengono eseguiti fuori dal rendering, quindi React non ha bisogno di un confine per riprendersi. Usa try/catch nel gestore, e se vuoi che compaia il confine, memorizza l'errore nello stato e generalo durante il rendering.
Gli error boundary intercettano gli errori asincroni?
Non da setTimeout, dalle callback delle promise o da fetch().then() che avvii tu. Intercettano invece una promise rifiutata letta con use e, in React 19, un errore generato dentro una form action o in una funzione passata allo startTransition di useTransition.
Come azzero un error boundary?
Azzera il suo stato di errore, di solito da un pulsante Try again nel fallback, dopo aver sistemato ciò che ha causato l'errore. Anche cambiare la key del confine lo azzera, perché React monta una nuova istanza.