
Gestion des erreurs (Error Boundaries)
Apprenez à utiliser les Error Boundaries (périmètres de gestion d'erreurs) en React pour intercepter les erreurs JavaScript dans vos composants et afficher une UI de repli.
Le problème : Une erreur JavaScript qui fait planter toute l'UI
Par défaut, si une erreur JavaScript se produit pendant le rendu d'un composant React, lors d'une mise à jour d'état, ou dans un de ses cycles de vie, cette erreur peut se propager vers le haut de l'arbre de composants et, si elle n'est pas interceptée, finir par démonter complètement toute l'application React. L'utilisateur se retrouve alors face à une page blanche ou à une interface cassée, sans aucune indication claire de ce qui s'est passé.
Ce comportement est évidemment indésirable. Une erreur dans une petite partie de l'interface utilisateur (par exemple, un widget annexe, un commentaire mal formaté) ne devrait idéalement pas faire planter l'intégralité de l'application. Il serait préférable de pouvoir intercepter ces erreurs à un certain niveau, d'afficher un message d'erreur ou une interface utilisateur de repli (fallback UI) à la place du composant défaillant, tout en laissant le reste de l'application fonctionner normalement.
C'est exactement le rôle des Error Boundaries (périmètres de gestion d'erreurs) en React.
Qu'est-ce qu'une Error Boundary ?
Une Error Boundary est un composant React spécial qui peut intercepter les erreurs JavaScript survenant n'importe où dans son arbre de composants enfants (descendants). Une fois l'erreur interceptée, l'Error Boundary peut enregistrer cette erreur et afficher une interface utilisateur de repli au lieu de l'arbre de composants qui a planté.
Techniquement, une Error Boundary est un composant classe (car les hooks ne permettent pas encore d'implémenter ce comportement spécifique) qui définit au moins l'une des deux méthodes de cycle de vie suivantes (ou les deux) :
static getDerivedStateFromError(error): Cette méthode statique est appelée pendant la phase de "rendu" après qu'une erreur a été levée par un composant descendant. Elle doit retourner un objet pour mettre à jour l'état du composant Error Boundary, ce qui lui permettra ensuite d'afficher l'UI de repli lors du prochain rendu. Elle est utilisée pour le rendu du fallback UI.componentDidCatch(error, errorInfo): Cette méthode est appelée pendant la phase de "commit" après qu'une erreur a été levée. Elle reçoit l'objet d'erreur et un objet `errorInfo` contenant la trace de la pile des composants (component stack trace) qui indique quel composant a généré l'erreur. Elle est idéale pour enregistrer (logger) les détails de l'erreur vers un service de suivi externe (comme Sentry, LogRocket, etc.). Elle n'est pas utilisée pour mettre à jour l'état en vue d'afficher un fallback.
Il est important de noter qu'une Error Boundary n'intercepte que les erreurs survenant dans les composants en dessous d'elle dans l'arbre. Elle n'intercepte pas les erreurs qui se produisent :
- A l'intérieur d'elle-même.
- Dans les gestionnaires d'événements (event handlers) - utilisez des `try...catch` classiques pour ceux-là.
- Dans le code asynchrone (ex: callbacks de `setTimeout`, requêtes API) - utilisez des `try...catch` ou les mécanismes d'erreur des Promesses.
- Dans le rendu côté serveur (SSR).
Implémentation d'une Error Boundary
Voici un exemple typique d'un composant Error Boundary simple :
import React, { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
// Méthode pour mettre à jour l'état et afficher le fallback UI
static getDerivedStateFromError(error) {
// Met à jour l'état pour que le prochain rendu affiche l'UI de repli.
return { hasError: true, error: error };
}
// Méthode pour logger les détails de l'erreur
componentDidCatch(error, errorInfo) {
// Vous pouvez aussi enregistrer l'erreur vers un service de reporting
console.error("Erreur interceptée par ErrorBoundary:", error, errorInfo);
// logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) {
// Vous pouvez rendre n'importe quelle UI de repli
return (
Oops ! Quelque chose s'est mal passé.
Nous avons été notifiés de l'erreur. Veuillez rafraîchir la page ou réessayer.
{/* Optionnel: Afficher les détails de l'erreur en développement */}
{process.env.NODE_ENV === 'development' && (
{this.state.error && this.state.error.toString()}
{/* errorInfo contient la trace des composants, pas disponible ici */}
{/* Vous pouvez la stocker dans l'état depuis componentDidCatch si besoin */}
)}
);
}
// Si pas d'erreur, rendre les composants enfants normalement
return this.props.children;
}
}
export default ErrorBoundary;Utilisation et placement stratégique
Une fois votre composant `ErrorBoundary` défini, vous l'utilisez en enveloppant les parties de votre application que vous souhaitez protéger. Le placement est crucial :
- Envelopper toute l'application : Vous pouvez placer une `ErrorBoundary` tout en haut de votre arbre (par exemple, dans `App.js` ou `index.js`). Cela interceptera toutes les erreurs de rendu mais affichera un message d'erreur pour toute l'application si une erreur survient.
- Envelopper des sections spécifiques : Une approche plus granulaire consiste à envelopper des sections indépendantes de votre UI (barre latérale, widget spécifique, contenu principal, routes individuelles) avec des `ErrorBoundary`. Si une erreur se produit dans un widget, seule cette partie affichera l'UI de repli, tandis que le reste de l'application restera fonctionnel. C'est souvent la stratégie préférée.
- Envelopper des composants tiers : Utile si vous utilisez une bibliothèque externe dont vous n'êtes pas sûr de la stabilité.
import ErrorBoundary from './ErrorBoundary';
import WidgetA from './WidgetA';
import WidgetB from './WidgetB'; // Supposons que WidgetB peut parfois planter
function MonDashboard() {
return (
Tableau de bord
{ /* Protège spécifiquement WidgetB */}
{ /* Non protégé ici */}
);
}
// Utilisation autour des routes (dans la config de React Router)
//
// }
// />
//
Le choix du placement dépend du niveau de granularité que vous souhaitez pour la gestion des erreurs et de l'impact qu'une erreur dans une partie doit avoir sur le reste de l'application.
Approches modernes avec des bibliothèques
Bien que l'implémentation de base d'une Error Boundary nécessite un composant classe, il existe des bibliothèques tierces qui facilitent leur utilisation dans un environnement basé sur les hooks. La plus populaire est react-error-boundary.
Elle fournit un composant `
import { ErrorBoundary } from 'react-error-boundary';
function ErrorFallback({ error, resetErrorBoundary }) {
return (
Quelque chose s'est mal passé:
{error.message} );}function MonApp() { return ( { // Logique pour réinitialiser l'état de l'app si nécessaire }} onError={(error, info) => logErrorToService(error, info.componentStack)} > );}Cette bibliothèque simplifie l'utilisation des Error Boundaries sans avoir à écrire explicitement des composants classe.
En conclusion, les Error Boundaries sont un mécanisme essentiel de React pour créer des applications plus résilientes. Elles permettent d'isoler les erreurs JavaScript survenant pendant le rendu dans des parties spécifiques de l'interface, d'afficher une UI de repli conviviale et d'enregistrer les erreurs pour le débogage, empêchant ainsi qu'une erreur locale ne fasse planter toute l'application.