Maison  >  Article  >  interface Web  >  GlobalErrorHandler : détectez les erreurs qui tombent entre les doigts d'ErrorBoundary !

GlobalErrorHandler : détectez les erreurs qui tombent entre les doigts d'ErrorBoundary !

Linda Hamilton
Linda Hamiltonoriginal
2024-10-21 20:39:29552parcourir

GlobalErrorHandler: Catch the errors that falls through ErrorBoundary

ErrorBoundary est un magnifique outil pour capturer les erreurs générées par les composants React. Vous pouvez fournir des messages d'erreur personnalisés en fonction de la nature et de l'emplacement de l'erreur elle-même. Mais toutes les erreurs générées ne sont pas gérées par ErrorBoundary ! Que fais-tu avec ça ?

Lorsque l'on considère à la fois les erreurs asynchrones et les erreurs générées depuis l'extérieur de React, le ErrorBoundary est insuffisant. Pour atténuer cela, j'ai créé dans mes applications ce que j'appelle un GlobalErrorHandler. Un composant fonctionnel qui A) affiche simplement une boîte de dialogue d'erreur, indiquant à l'utilisateur que quelque chose s'est mal passé, B) enregistre l'erreur sur le serveur, afin que nous puissions enquêter et trouver des solutions.

L'idée est simple. Nous voulons un GlobalErrorHandler à la racine de notre application. Ce gestionnaire ne doit gérer que les erreurs non détectées par ErrorBoundary. De plus, il devrait être facilement ignoré par l'utilisateur, et nous devrions supposer que l'application est toujours utilisable.

La stratégie est donc la suivante : le GlobalErrorHandler ne fait rien du tout, sauf le rendu de ses enfants, par défaut. Mais il configure deux écouteurs d'événements, à l'écoute de tous les événements d'erreur et de rejet non gérés dans le navigateur. Ensuite, il examine l'erreur et voit si elle a déjà été traitée par un ErrorBoundaries. Enfin, si ce n'est pas le cas, une boîte de dialogue apparaît, indiquant à l'utilisateur que quelque chose s'est mal passé quelque part, et permet à l'utilisateur de fermer la boîte de dialogue et de continuer à utiliser l'application.

L'erreur a-t-elle déjà été traitée

Avant de harceler les utilisateurs finaux avec des boîtes de dialogue inutiles EN PLUS de la gestion effectuée par ErrorBoundary, nous devons d'abord commencer par demander l'erreur : Avez-vous déjà été traité ? Ma solution à cela consiste à introduire un nouveau champ sur l'objet d'erreur isHandledByBoundary. Ceci est défini sur true dans ErrorBoundary :

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    (error as any).isHandledByBoundary = true;
    ....
  }

Avec cela en place dans tous les composants ErrorBoundary (et autres machines qui gèrent les erreurs non détectées), nous sommes prêts à commencer à définir notre GlobalErrorHandler.

Le squelette nu

Ensuite, nous pouvons construire le squelette de notre GlobalErrorHandler. Il restitue directement ses enfants et restitue également un "ErrorDialog" défini ailleurs. (Si vous souhaitez partager ce composant entre applications, ErrorDialog pourrait être un accessoire à la place.)

import { useState, useEffect, ReactNode } from 'react';
import { ErrorDialog } from '../Components/ErrorDialog';

type Props = {
  children: ReactNode;
};

export function GlobalErrorHandler({ children }: Props) {
  const [error, setError] = useState<Error | string | null>(null);
  const [isDialogOpen, setDialogOpen] = useState(false);

  useEffect(() => {
    ....
  }, []);

  function handleCloseDialog() {
    setDialogOpen(false);
    setError(null);
  }

  return (
    <>
      {children}

      {isDialogOpen && error && (
        <ErrorDialog
          actionName="Unhandled error"
          error={error}
          loggFeilmelding={true}
          onClose={handleCloseDialog}
        />
      )}
    </>
  );
}

La seule chose qui nous manque maintenant, c'est la gestion des erreurs elle-même, définie dans useEffect.

Gérer les erreurs

Tout le code de cette section doit être situé dans la fonction useEffect !

Nous définissons d’abord handleWindowError. Ceci doit être transmis au gestionnaire d'événements d'erreur sur l'objet fenêtre. Rien de mystérieux ici, mais soyez témoin que l'événement d'erreur contient également des informations sur la source, le numéro de ligne et le numéro de colonne. Ce qui pourrait être précieux à collectionner.

Habituellement, ces informations se trouvent également dans l'objet d'erreur, mais je dois mener des enquêtes plus empiriques à ce sujet. Peut-être devrions-nous toujours conserver les numéros de ligne et de colonne tels que rapportés par l'événement d'erreur ? Dans ce cas, nous pourrions également avoir un état pour cela dans GlobalErrorHandler (et nous assurer qu'il est envoyé lors de la journalisation de l'erreur).

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    (error as any).isHandledByBoundary = true;
    ....
  }

Nous définirons également le gestionnaire handleUnhandledRejection. Ceci concerne les erreurs qui sont générées dans les promesses, mais pour lesquelles nous avons oublié d'écrire une clause .catch().

import { useState, useEffect, ReactNode } from 'react';
import { ErrorDialog } from '../Components/ErrorDialog';

type Props = {
  children: ReactNode;
};

export function GlobalErrorHandler({ children }: Props) {
  const [error, setError] = useState<Error | string | null>(null);
  const [isDialogOpen, setDialogOpen] = useState(false);

  useEffect(() => {
    ....
  }, []);

  function handleCloseDialog() {
    setDialogOpen(false);
    setError(null);
  }

  return (
    <>
      {children}

      {isDialogOpen && error && (
        <ErrorDialog
          actionName="Unhandled error"
          error={error}
          loggFeilmelding={true}
          onClose={handleCloseDialog}
        />
      )}
    </>
  );
}

Ensuite, tout ce que nous devons faire est de configurer les écouteurs et de les supprimer chaque fois que GlobalErrorHandler n'est plus rendu :

   function handleWindowError(
      message: string | Event,
      source?: string,
      lineno?: number,
      colno?: number,
      error?: Error
    ) {
      if (error && (error as any).isHandledByBoundary) {
        return true;
      }

      const errorMessage = error
        ? error
        : `Error: ${message} at ${source}:${lineno}:${colno}`;
      setError(errorMessage);
      setDialogOpen(true);
      return true;
    }

Les instructions return sont, bien sûr, l'endroit où nous revenons de la fonction que nous alimentons useEffect. Cela garantit que nous commençons à écouter les événements et à les gérer lorsque le composant est rendu, et que nous nous arrêtons lorsque le composant n'est plus rendu.

Nous avons donc un GlobalEventHandler, pour gérer ces erreurs embêtantes dans notre application React qui sont soit générées à partir de sources asynchrones, soit générées depuis l'extérieur des composants React !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn