Come gestire gli errori in React

La corretta gestione degli errori è una parte essenziale di un software ben progettato. In questo articolo vedremo una panoramica sulla gestione degli errori nelle applicazioni React e su come utilizzare i Contenitori di Errori di React per gestire gli errori di rendering.

Maico Orazio
weBeetle
5 min readDec 14, 2021

--

Contenitori di Errori

Gli sviluppatori front-end spesso trascurano la gestione degli errori. Tuttavia, se un segmento di codice genera un errore, è necessario gestirlo correttamente. Inoltre, a seconda della situazione, ci sono diversi modi per farlo in React. Iniziamo.

Gestione degli errori

La corretta gestione degli errori è fondamentale per il normale funzionamento delle applicazioni. Sostanzialmente possiamo dividere gli errori in due tipi:

  • Errori di JavaScript
  • Errori di rendering

Gli errori di JavaScript si verificano nel codice. Ne rappresentano un esempio gli errori nei gestori di eventi e nelle callback asincrone. Mentre questi possono essere gestiti con i blocchi try-catch, per gli errori di rendering, React fornisce una gestione specializzata: i Contenitori di Errori.

Diamo un’occhiata alle diverse pratiche sulla gestione degli errori:

# Gestione degli errori con i Contenitori di Errori di React

L’idea alla base dei contenitori di errori è che puoi racchiudere qualsiasi parte della tua applicazione in un componente speciale, un cosiddetto contenitore di errore; se quella parte dell’applicazione riscontra un errore non rilevato, sarà contenuto all’interno di quello specifico componente. Puoi quindi mostrare un errore, segnalarlo al tuo servizio di segnalazione errori preferito e provare a ripristinarlo, se possibile.

I Contenitori di Errori , introdotti con React 16, sono il modo più diretto ed efficace per gestire gli errori che si verificano all’interno dei componenti di React. È l’unico componente che devi ancora scrivere come componente di classe -quindi nessun hook per ora!- ma dovrebbe sicuramente far parte di qualsiasi moderna applicazione React.

È possibile creare un nuovo componente di classe per rilevare errori di rendering ovunque nell’albero dei componenti di React e visualizzare un’interfaccia utente di fallback in caso di tali errori. Di solito implementa uno o entrambi i metodi del ciclo di vita:

componentDidCatch(error, info) chiamato ogni volta che si verifica un errore e utilizzato per registrare le informazioni sull’errore, la funzione statica getDerivedStateFromError(error) utilizzata per aggiornare lo stato e il metodo render() per visualizzare una vista di fallback se si verifica un errore.

Di seguito un esempio:

import React from 'react'class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.log(error);
console.log(errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Oops, something went wrong.</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;

Dopodiché, devi solo avvolgere i componenti all’interno del componente ErrorBoundary creato sopra:

<ErrorBoundary>
<MyComponent />
</ErrorBoundary>

Se si verifica un errore al di fuori di un contenitore di errore, l’intero albero dei componenti di React verrà smontato, causando l’arresto anomalo dell’applicazione.

Pertanto, assicurati che i componenti soggetti a errori siano racchiusi in un contenitore di errore.

Sebbene i contenitori di errore siano un modo eccellente per gestire gli errori, presentano alcuni inconvenienti. Ad esempio, il metodo del ciclo di vita componentDidCatch(error, info) viene chiamato solo se si verifica un errore durante il rendering, nei metodi del ciclo di vita o nei costruttori di qualsiasi componente figlio del componente.

Di conseguenza, i componenti di errori non possono gestirli nei gestori di eventi -perdonate il giro di parole!-, nelle callback asincrone o nel rendering lato server.

#Gestione degli errori con Try-Catch

Gli errori JavaScript vengono gestiti avvolgendo il codice in blocchi try-catch. Questo è un bene compreso e funziona alla grande, ma ci sono alcune precisazioni da fare nel contesto di un’interfaccia utente di React.

Innanzitutto, è importante notare che questi errori non si propagano ai contenitori di errori. I blocchi try-catch non sono il modo migliore per gestire le eccezioni a livello di componente perché non catturano le eccezioni a cascata dai componenti figlio.

Tuttavia, i blocchi try-catch vengono utilizzati per gestire gli errori che non vengono rilevati dai contenitori di errori.

Considera uno scenario di recupero todos in cui effettuiamo una chiamata asincrona a un’API. Possiamo usare il blocco try-catch e React per gestire eventuali errori che possono verificarsi:

import React, { useState, useEffect } from "react";const App = () => {
const [todos, setTodos] = useState([]);
const [isError, setError] = useState(false);
useEffect(() => {
const fetchData = async () => {
let response = await fetch("https://jsonplaceholder.typicode.com/todos");
let data = await response.json();
setTodos(data.slice(0, 10));
};
try {
fetchData();
}
catch(error) {
setError(true);
}

}, []);
return (
<div>
<ul>
{todos.map((todo, i) => (
<li key={i}>{todo.title}</li>
))}
</ul>
</div>
);
};
export default App;

#Libreria react-error-boundary — il modo migliore

La libreria react-error-boundary semplifica notevolmente la gestione degli errori in React ed è la soluzione più efficace per superare i limiti dei contenitori di errore.

Ti consente di visualizzare un componente di fallback, registrare gli errori e ripristinare lo stato dell’applicazione, in modo che l’errore non si ripeta.

import { ErrorBoundary } from 'react-error-boundary'function ErrorFallback({ error, resetErrorBoundary }) {
return (
<div role="alert">
<p>There was an error:</p>
<pre style={{ whiteSpace: 'normal' }}>{error.message}</pre
<button type="button" onClick={resetErrorBoundary}>
Try again
</button>
</div>
)
}
const App = () => {
const handleReset = () => {
console.log('RESET ERROR')
}
return (
<ErrorBoundary
FallbackComponent={ErrorFallback}
onError={(error, errorInfo) => {
console.log(error)
console.log(errorInfo )
}}
onReset={handleReset}
>
<MyComponent />
</ErrorBoundary>
);
}
export default App;

Nel codice sopra, avvolgiamo semplicemente il nostro componente MyComponent con il componente ErrorBoundary e passiamo il nostro componente di fallback ErrorFallback in modo che se si verifica un errore (che può essere catturato e gestito da react-error-boundary), il nostro componente di fallback sarà reso; in caso contrario, verrà eseguito il rendering del nostro componente MyComponent.

Il componente ErrorBoundary ha anche una prop onError, che viene attivato quando il nostro contenitore di errore rileva e gestisce un errore nei suoi componenti figlio. È in questo punto che potremmo scegliere di registrare tali errori su qualsiasi servizio di registrazione degli errori.

react-error-boundary fornisce anche un modo per recuperare dagli errori rilevati dai nostri contenitori di errore. Questa operazione viene eseguita utilizzando i bottoni di ripristino e la funzione resetErrorBoundary passata al componente di fallback.

L’hook useErrorHandler

Ancora più importante, ora è possibile gestire gli errori nei gestori di eventi e nelle callback asincrone utilizzando l’hook useErrorHandler(). Se l’hook useErrorHandler(true) viene chiamato con un valore true, quindi per indicare il verificarsi di un errore, react-error-boundary lo propagherà alla funzione di gestione errore più vicina.

Quindi, puoi utilizzare react-error-boundary per eliminare la necessità di due diversi metodi di gestione degli errori nella tua app.

Conclusione

Qualsiasi applicazione di alta qualità deve gestire errori ed eventi imprevisti. Gli errori devono essere gestiti e registrati in modo appropriato per aiutarti a determinare la causa principale, con il minimo impatto sull’esperienza dell’utente.

In questo articolo abbiamo discusso di vari approcci che potrebbero essere utilizzati per raggiungere questo obiettivo, spero che ti aiuteranno a sviluppare applicazioni React più robuste.

Grazie per la lettura!

--

--

Maico Orazio
weBeetle

Senior Web Application Developer. I'm a software engineer, a passionate coder, and a web developer. I am a fan of technology. #php #symfony #javascript #reactjs