Comment gérer les erreurs côté serveur

Gestion des erreurs 404 et ErrorBoundary : apprends à sécuriser tes routes dynamiques React Router 7 et à renvoyer des réponses HTTP propres.

4 min read
Déverrouillez votre potentiel

avec React Router 7

Vous en avez marre de...

❌ perdre du temps à chercher des informations éparpillées
❌ ne pas avoir de retour sur votre progression
Assistant IA spécialisé

Posez vos questions 24/7 à notre IA experte en React Router 7

Quiz interactifs

Validez vos acquis avec des quiz personnalisés et un feedback instantané

9 modules
45 leçons
Accès à vie
299.00
-50%

Dans React Router 7, chaque route peut renvoyer une erreur contrôlée depuis le loader ou l’action sans planter toute l'application. Au lieu d’afficher une page blanche, on renvoie un objet Response avec un code HTTP et un message, et on intercepte ce cas dans un ErrorBoundary dédié. Ce pattern améliore l’UX et facilite le débogage.

1. Créer une route dynamique

On part d’une route qui affiche le détail d’un utilisateur à partir de son slug :

app/routes/users.$userSlug.tsx
1
import {
2
isRouteErrorResponse,
3
useLoaderData,
4
useRouteError,
5
type LoaderFunctionArgs,
6
} from 'react-router'
7
import { getUserBySlug } from '~/users.server'
8
9
export async function loader({ params }: LoaderFunctionArgs) {
10
const user = await getUserBySlug({ slug: params.userSlug })
11
if (!user) {
12
// ^? On lève une Response pour renvoyer une erreur HTTP contrôlée
13
// @callout: throw new Response déclenche isRouteErrorResponse()
14
throw new Response(`User "${params.userSlug}" was not found`, {
15
status: 404,
16
statusText: 'Not Found',
17
})
18
}
19
return { user }
20
}
21
22
export default function UserDetail() {
23
const { user } = useLoaderData<typeof loader>()
24
return (
25
<div className="p-4">
26
<h1 className="text-2xl font-bold">{user.name}</h1>
27
<p>ID: {user.id}</p>
28
</div>
29
)
30
}
  • On importe LoaderFunctionArgs et useLoaderData depuis <Link to="https://reactrouter.com/api/hooks">react-router</Link>.
  • Si l’utilisateur n’existe pas, on throw une instance de Response avec un status et statusText.
  • React Router retient ce Response et le transmet à l’ErrorBoundary.

2. Personnaliser l’ErrorBoundary de la route

On ajoute un export ErrorBoundary dans le même fichier pour capturer uniquement les erreurs de cette route :

app/routes/users.$userSlug.tsx
1
export function ErrorBoundary() {
2
const error = useRouteError()
3
4
if (isRouteErrorResponse(error)) {
5
return (
6
<div className="h-screen flex flex-col items-center justify-center p-4">
7
<h1 className="text-3xl font-bold text-red-600">
8
{error.status} {error.statusText}
9
</h1>
10
<p className="mt-2 text-red-500">{error.data}</p>
11
</div>
12
)
13
}
14
15
if (error instanceof Error) {
16
return (
17
<div className="h-screen flex flex-col items-center justify-center p-4">
18
<h1 className="text-3xl font-bold text-red-600">Erreur</h1>
19
<p className="mt-2 text-red-500">{error.message}</p>
20
</div>
21
)
22
}
23
24
return <h1>Une erreur inconnue est survenue.</h1>
25
}
  • useRouteError() rend l’erreur levée par le loader/action.
  • isRouteErrorResponse(error) repère les Response contrôlées.
  • En mode development, tu peux aussi afficher la stack trace.

3. Gérer le 404 et les autres statuts

Dans users.server.ts, la fonction getUserBySlug renvoie undefined si pas trouvé :

app/users.server.ts
1
const db = {
2
users: [
3
{ id: 1, name: 'Virgile', slug: 'virgile' },
4
{ id: 2, name: 'Robert', slug: 'robert' },
5
// …
6
]
7
}
8
9
export async function getUserBySlug({ slug }: { slug: string }) {
10
// Simule un délai réseau
11
await new Promise(r => setTimeout(r, 100))
12
return db.users.find(u => u.slug === slug)
13
}

Le loader l’appelle, puis génère un 404 pour un slug manquant. Pour d’autres erreurs (500, 403), le pattern est identique : on lève une Response avec le code adapté.

4. Fallback global dans root.tsx

Pour toutes les erreurs non capturées localement, on a un ErrorBoundary global dans app/root.tsx :

app/root.tsx
1
import { isRouteErrorResponse, Link, Outlet } from 'react-router'
2
3
export function ErrorBoundary({ error }: { error: unknown }) {
4
let title = 'Oops!'
5
let message = 'Une erreur inattendue est survenue.'
6
7
if (isRouteErrorResponse(error)) {
8
title = error.status === 404 ? '404 – Introuvable' : `Erreur ${error.status}`
9
message = error.data || error.statusText || message
10
} else if (error instanceof Error) {
11
message = error.message
12
}
13
14
return (
15
<div className="container mx-auto p-4">
16
<h1 className="text-4xl font-bold text-red-600 mb-2">{title}</h1>
17
<p className="text-lg text-gray-700">{message}</p>
18
<Link to="/" className="text-blue-500 hover:underline mt-4 block">
19
Retour à l’accueil
20
</Link>
21
</div>
22
)
23
}

Points clés

  • Loader vs. action : utilisez throw new Response(...) dans loader/action
    pour renvoyer un statut HTTP contrôlé (404, 403, 500…).
  • ErrorBoundary : déclarez-en un par route pour personnaliser le rendu
    ou un global dans root.tsx pour attraper le reste.
  • useRouteError + isRouteErrorResponse : distinguez facilement
    vos erreurs contrôlées des exceptions inattendues.
  • En mode dev, affichez la stack trace ; en prod, simplifiez l’affichage.

Exercices rapides

  1. Ajouter une vérification d’autorisation dans loader :
    • Si l’utilisateur n’a pas un rôle "admin", throw une Response 403.
    • Affichez un message personnalisé dans l’ErrorBoundary local.
  2. Gérer une erreur serveur inattendue :
    • Dans getUserBySlug, lancez throw new Error("DB inaccessible").
    • Vérifiez que le ErrorBoundary global intercepte et affiche un message générique.
  3. Créer une route /settings :
    • Si la fonctionnalité est désactivée, renvoyez un Response 410 (Gone).
    • Affichez un message dédié expliquant la suppression de la page.
Premium
Quiz interactif
Testez vos connaissances et validez votre compréhension du module avec notre quiz interactif.
1

Comprendre les concepts fondamentaux

Quelle est la principale différence entre les composants client et serveur dans React ?

Les composants client s'exécutent uniquement dans le navigateur
Les composants serveur peuvent utiliser useState
Les composants client sont plus rapides
Il n'y a aucune différence significative
2

Optimisation des performances

Quelle technique est recommandée pour éviter les rendus inutiles dans React ?

Utiliser React.memo pour les composants fonctionnels
Ajouter plus d'états locaux
Éviter d'utiliser les props
Toujours utiliser les class components
3

Architecture des données

Quel hook permet de gérer les effets de bord dans un composant React ?

useEffect
useState
useMemo
useContext
4

Gestion des erreurs

Comment implémenter la gestion des erreurs pour les requêtes API dans React ?

Utiliser try/catch avec async/await
Ignorer les erreurs
Toujours afficher un message d'erreur
Rediriger l'utilisateur
5

Déploiement et CI/CD

Quelle est la meilleure pratique pour déployer une application React en production ?

Utiliser un service CI/CD comme GitHub Actions
Copier les fichiers manuellement via FTP
Envoyer le code source complet
Ne jamais mettre à jour l'application

Débloquez ce quiz et tous les autres contenus premium en achetant ce cours