Retour aux articles

Comment gérer les erreurs avec Remix ? (ErrorBoundary)

Gère les erreurs avec le framework Remix.js
6 minutes de lecture

As-tu déjà eu des erreurs Javascript en production ? Pire encore, as-tu reçu l'appel d'un client, qui se plaint d'avoir reçu un message d'erreur ? Tu perds de la crédibilité.

Heureusement, il existe le composant ErrorBoundary qui permet d'afficher un composant d'erreur, respectant le thème du site et ton Design System.

Avant d'utiliser ErrorBoundaryHeader Icon

Tu retrouves un message d'erreur générique incompréhensible. Difficile de comprendre ce qui a pu se passer, et tu vas prendre du temps à réparer le bug. De plus, ton site est inutilisable en l'état. La navigation de ton utilisateur a été coupée brutalement.

Erreur générique Javascript

Après avoir mis en place ErrorBoundaryHeader Icon

Tu améliores l'expérience utilisateur. Tu réduis l'impact de l'erreur à l'endroit où elle a été déclenchée. Cela permet au développeur de vite résoudre le problème, car il sait exactement de quel fichier il s'agit.

Dans Remix, on utilise le composant ErrorBoundary, qui va remplacer le composant ayant déclenché l'erreur.

Message d'erreur Remix localisé, clair et concis, ne perturbant pas le parcours utilisateur

Tu retrouves cet exemple et davantage d'information dans la documentation de Remix concernant l'error handling

Pour améliorer l'expérience utilisateur (UX), il est recommandé d'offrir une explication claire dans le message d'erreur, comme expliqué dans la figure ci-dessous (Source).

Erreur Javascript personnalisée, rassurant le client et expliquant ce qui s'est passé

Un message d'erreur idéal :

  • rassure le client
  • explique la raison du problème
  • offre une marche à suivre pour arranger les choses (contacter le support)

Qu'est-ce que le composant ErrorBoundary ?Header Icon

C'est une librairie Javascript, disponible sur NPM sous le nom de react-error-boundary. Elle est téléchargée plus de 3,7 millions de fois par semaine.

Pour l'utiliser dans une application React standard, il suffit de la télécharger dans ton projet :

Terminal

_10
npm install react-error-boundary

Ensuite, tu l'utilises dans un composant React. Elle va englober le composant qui risque de déclencher une erreur, et afficher un composant fallback à la place.

example.tsx

_10
import { ErrorBoundary } from 'react-error-boundary';
_10
_10
<ErrorBoundary fallback={<div>Something went wrong</div>}>
_10
<ExampleApplication />
_10
</ErrorBoundary>;

Cet exemple montre deux composants :

  • Le composant parent ErrorBoundary, qui prend un children (le composant enfant) et une propriété fallback (affichant le composant d'erreur)
  • Le composant enfant ExampleApplication. En cas d'erreur de ce dernier, l'erreur ne va pas remonter à la racine de l'application. À la place, l'erreur va afficher le composant fallback.

Il y a une deuxième manière d'utiliser ce composant, offrant plus de contrôle et une meilleure UX.

example.tsx

_21
import { ErrorBoundary } from 'react-error-boundary';
_21
_21
function fallbackRender({ error, resetErrorBoundary }) {
_21
// Call resetErrorBoundary() to reset the error boundary and retry the render.
_21
_21
return (
_21
<div role='alert'>
_21
<p>Something went wrong:</p>
_21
<pre style={{ color: 'red' }}>{error.message}</pre>
_21
</div>
_21
);
_21
}
_21
_21
<ErrorBoundary
_21
fallbackRender={fallbackRender}
_21
onReset={(details) => {
_21
// Reset the state of your app so the error doesn't happen again
_21
}}
_21
>
_21
<ExampleApplication />
_21
</ErrorBoundary>;

La propriété fallbackRender accepte une fonction fléchée, nous permettant de récupérer deux arguments :

  • Les informations sur l'erreur qui a été déclenchée
  • Une fonction permettant de ré-effectuer un rendu du composant. Déclencher cette fonction permet d'annuler l'erreur, et d'afficher le composant enfant.

Généralement, on laisse l'utilisateur appeler cette méthode resetErrorBoundary. Plus haut, par exemple en utilisant le bouton Try Again.

Mais cet article ne se concentre pas sur ce composant très utile.

Si tu utilises Remix, tu n'as même pas besoin de l'utiliser.

Il est intégré directement dans la librairie !

Comment gérer tes erreurs avec RemixHeader Icon

Pour déclencher une erreur dans ton application Remix, il te suffit d'ajouter l'instruction throw new Error('bam') sur n'importe quelle route active.

Ce qui affiche ceci :

Une erreur dans une application Remix

Cette erreur n'est pas claire du tout. Et elle rend ton application inutilisable pour les clients : Ils ne peuvent pas accéder à une autre page depuis l'interface.

De plus, cela ne t'aide pas à connaître la raison de l'erreur : elle pourrait être déclenchée par n'importe quoi.

Comment faire ? Il suffit d' exporter un composant nommé ErrorBoundary dans ton application Remix. Commence par l'importer dans le fichier root.tsx, se situant dans le dossier app/routes de ton projet Remix.

Le composant ErrorBoundary (Remix)Header Icon

Le composant ErrorBoundary est une convention de Remix (au même titre que les méthodes loader et action). Exporter un composant nommé "ErrorBoundary" dans n'importe quelle route indique à Remix qu'en cas d'erreur, il doit afficher son contenu, et ne pas propager l'erreur plus haut.

Prenons par exemple l'export ci-dessous :

app/routes/root.tsx

_10
export function ErrorBoundary() {
_10
const error = useRouteError();
_10
let errorMessage = 'Une erreur inattendue est survenue';
_10
_10
if (error instanceof Error) {
_10
errorMessage = error.message;
_10
}
_10
_10
return <div>{errorMessage}</span>;
_10
}

Après avoir ajouté ces quelques lignes, notre application ressemble à ça :

Notre application Remix affiche le message d'erreur "bam"

On avait rajouté la ligne throw new Error('bam');. Au lieu d'afficher l'erreur en rouge, sans design, notre composant ErrorBoundary est affiché.

Cela nous apporte quelques bénéfices :

  • L'erreur ne se propage pas au dessus (on y revient un peu plus bas)
  • On peut designer notre message d'erreur, expliquer au client ce qui s'est passé, et lui indiquer la marche à suivre
  • En bonus, on peut sauvegarder cette erreur avec un outil comme Sentry, ou l'envoyer par email pour être prévenu si jamais elle est déclenchée en production.

Les erreurs ne remontent pasHeader Icon

React utilise un système de composants, avec des balises imbriquées. Ce qui donne une hiérarchie avec des "parents" et des "enfants".

Avec Remix, il est possible d'implémenter des routes imbriquées. Cela signifie qu'il est possible d'avoir plusieurs routes actives en même temps.

C'est ce que nous montre l'image, que nous avions vu au dessus :

Message d'erreur Remix localisé, clair et concis, ne perturbant pas le parcours utilisateur

Cette image représente une route imbriquée. Quatres routes sont actuellement actives :

  • La route root principale. C'est notre composant d'entrée, cette route est rendue sur toutes les routes. La route root affiche la barre latérale, sur le côté gauche.
  • La route sales (on la voit comme premier segment dans l'URL) affiche le titre de la page "Sales", ainsi qu'une barre de navigation horizontale.
  • La route invoices (on retrouve son segment dans l'URL) est "enfant" de la route Sales, et affiche les statistiques globales, la barre jaune et verte ainsi que le tableau de factures
  • La route dynamique 102000 (où 102000 représente une id de facture) est imbriquée dans invoices (encore une fois, on le constate grâce au segment d'URL final). C'est le dernier enfant de cette hiérarchie, l'enfant le plus bas. Et il est en erreur.

On peut symboliser cette vue d'une autre manière :


_10
export default function Page () {
_10
return (<Sales>
_10
<Invoices>
_10
<Invoice id="102000"/>
_10
</Invoices
_10
</Sales>)
_10
}

Chaque imbrication représente un enfant dans notre composant. Et le composant ErrorBoundary empêche notre erreur de remonter plus haut.

Ce qui est représenté par l'image ci-dessus, au final, est un message d'erreur qui a empêché une erreur déclenchée dans le composant Invoice de remonter plus haut.

C'est un peu comme s'il s'était passé la chose suivante :


_11
export default function Page() {
_11
return (
_11
<Sales>
_11
<Invoices>
_11
<ErrorBoundary fallback={<Error message='Something went wrong' />}>
_11
<Invoice id='102000' />
_11
</ErrorBoundary>
_11
</Invoices>
_11
</Sales>
_11
);
_11
}

Remix a remplacé le composant Invoice par un composant Error, car ce fichier était protégé par une fonction ErrorBoundary.

En ajoutant ce composant sur notre route imbriquée, nous améliorons considérablement l'expérience de nos utilisateurs. De plus, nos développeurs identifient plus rapidement le problème, car le composant en erreur est au plus bas dans la hiérarchie.

Articles similaires
Rejoins la
newsletter