error.js

Un fichier error vous permet de gérer les erreurs d'exécution inattendues et d'afficher une interface utilisateur de secours.

Fichier spécial error.js
'use client' // Les limites d'erreur doivent être des composants clients

import { useEffect } from 'react'

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  useEffect(() => {
    // Enregistrer l'erreur dans un service de rapport d'erreurs
    console.error(error)
  }, [error])

  return (
    <div>
      <h2>Quelque chose s'est mal passé !</h2>
      <button
        onClick={
          // Tentative de récupération en re-rendant le segment
          () => reset()
        }
      >
        Réessayer
      </button>
    </div>
  )
}
'use client' // Les limites d'erreur doivent être des composants clients

import { useEffect } from 'react'

export default function Error({ error, reset }) {
  useEffect(() => {
    // Enregistrer l'erreur dans un service de rapport d'erreurs
    console.error(error)
  }, [error])

  return (
    <div>
      <h2>Quelque chose s'est mal passé !</h2>
      <button
        onClick={
          // Tentative de récupération en re-rendant le segment
          () => reset()
        }
      >
        Réessayer
      </button>
    </div>
  )
}

error.js encapsule un segment de route et ses enfants dans une limite d'erreur React. Lorsqu'une erreur est levée dans cette limite, le composant error s'affiche comme interface utilisateur de secours.

Fonctionnement de error.js

Bon à savoir :

  • Les React DevTools permettent de basculer les limites d'erreur pour tester les états d'erreur.
  • Si vous souhaitez que les erreurs remontent à la limite d'erreur parente, vous pouvez utiliser throw lors du rendu du composant error.

Référence

Props

error

Une instance d'un objet Error transmise au composant client error.js.

Bon à savoir : En développement, l'objet Error transmis au client est sérialisé et inclut le message de l'erreur originale pour faciliter le débogage. Cependant, ce comportement diffère en production pour éviter de divulguer des détails potentiellement sensibles au client.

error.message

  • Les erreurs provenant de composants clients affichent le message original de Error.
  • Les erreurs provenant de composants serveurs affichent un message générique avec un identifiant. Ceci pour éviter de divulguer des détails sensibles. Vous pouvez utiliser l'identifiant, sous errors.digest, pour faire correspondre les journaux côté serveur.

error.digest

Un hachage généré automatiquement de l'erreur levée. Il peut être utilisé pour faire correspondre l'erreur dans les journaux côté serveur.

reset

La cause d'une erreur peut parfois être temporaire. Dans ces cas, une nouvelle tentative peut résoudre le problème.

Un composant d'erreur peut utiliser la fonction reset() pour inviter l'utilisateur à tenter de récupérer de l'erreur. Lorsqu'elle est exécutée, la fonction essaie de re-rendre le contenu de la limite d'erreur. Si elle réussit, le composant d'erreur de secours est remplacé par le résultat du nouveau rendu.

'use client' // Les limites d'erreur doivent être des composants clients

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <div>
      <h2>Quelque chose s'est mal passé !</h2>
      <button onClick={() => reset()}>Réessayer</button>
    </div>
  )
}
'use client' // Les limites d'erreur doivent être des composants clients

export default function Error({ error, reset }) {
  return (
    <div>
      <h2>Quelque chose s'est mal passé !</h2>
      <button onClick={() => reset()}>Réessayer</button>
    </div>
  )
}

Exemples

Erreur globale

Bien que moins courant, vous pouvez gérer les erreurs dans la mise en page ou le modèle racine en utilisant global-error.js, situé dans le répertoire racine de l'application, même lors de l'utilisation de l'internationalisation. L'interface utilisateur d'erreur globale doit définir ses propres balises <html> et <body>. Ce fichier remplace la mise en page ou le modèle racine lorsqu'il est actif.

'use client' // Les limites d'erreur doivent être des composants clients

export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    // global-error doit inclure les balises html et body
    <html>
      <body>
        <h2>Quelque chose s'est mal passé !</h2>
        <button onClick={() => reset()}>Réessayer</button>
      </body>
    </html>
  )
}
'use client' // Les limites d'erreur doivent être des composants clients

export default function GlobalError({ error, reset }) {
  return (
    // global-error doit inclure les balises html et body
    <html>
      <body>
        <h2>Quelque chose s'est mal passé !</h2>
        <button onClick={() => reset()}>Réessayer</button>
      </body>
    </html>
  )
}

Récupération élégante avec une limite d'erreur personnalisée

Lorsque le rendu échoue côté client, il peut être utile d'afficher le dernier rendu serveur connu pour une meilleure expérience utilisateur.

Le GracefullyDegradingErrorBoundary est un exemple de limite d'erreur personnalisée qui capture et préserve le HTML actuel avant qu'une erreur ne se produise. Si une erreur de rendu se produit, il re-rend le HTML capturé et affiche une barre de notification persistante pour informer l'utilisateur.

'use client'

import React, { Component, ErrorInfo, ReactNode } from 'react'

interface ErrorBoundaryProps {
  children: ReactNode
  onError?: (error: Error, errorInfo: ErrorInfo) => void
}

interface ErrorBoundaryState {
  hasError: boolean
}

export class GracefullyDegradingErrorBoundary extends Component<
  ErrorBoundaryProps,
  ErrorBoundaryState
> {
  private contentRef: React.RefObject<HTMLDivElement>

  constructor(props: ErrorBoundaryProps) {
    super(props)
    this.state = { hasError: false }
    this.contentRef = React.createRef()
  }

  static getDerivedStateFromError(_: Error): ErrorBoundaryState {
    return { hasError: true }
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    if (this.props.onError) {
      this.props.onError(error, errorInfo)
    }
  }

  render() {
    if (this.state.hasError) {
      // Rendu du contenu HTML actuel sans hydratation
      return (
        <>
          <div
            ref={this.contentRef}
            suppressHydrationWarning
            dangerouslySetInnerHTML={{
              __html: this.contentRef.current?.innerHTML || '',
            }}
          />
          <div className="fixed bottom-0 left-0 right-0 bg-red-600 text-white py-4 px-6 text-center">
            <p className="font-semibold">
              Une erreur s'est produite lors du rendu de la page
            </p>
          </div>
        </>
      )
    }

    return <div ref={this.contentRef}>{this.props.children}</div>
  }
}

export default GracefullyDegradingErrorBoundary
'use client'

import React, { Component, createRef } from 'react'

class GracefullyDegradingErrorBoundary extends Component {
  constructor(props) {
    super(props)
    this.state = { hasError: false }
    this.contentRef = createRef()
  }

  static getDerivedStateFromError(_) {
    return { hasError: true }
  }

  componentDidCatch(error, errorInfo) {
    if (this.props.onError) {
      this.props.onError(error, errorInfo)
    }
  }

  render() {
    if (this.state.hasError) {
      // Rendu du contenu HTML actuel sans hydratation
      return (
        <>
          <div
            ref={this.contentRef}
            suppressHydrationWarning
            dangerouslySetInnerHTML={{
              __html: this.contentRef.current?.innerHTML || '',
            }}
          />
          <div className="fixed bottom-0 left-0 right-0 bg-red-600 text-white py-4 px-6 text-center">
            <p className="font-semibold">
              Une erreur s'est produite lors du rendu de la page
            </p>
          </div>
        </>
      )
    }

    return <div ref={this.contentRef}>{this.props.children}</div>
  }
}

export default GracefullyDegradingErrorBoundary

Historique des versions

VersionChangements
v15.2.0Affiche également global-error en développement.
v13.1.0Introduction de global-error.
v13.0.0Introduction de error.