Cours JavaScript et React · Module 6: React Router

Les redirections dans la navigation cosmique

7 min de lecture
Dans cette leçon8

Imagine que la station spatiale a changé d'adresse : l'ancien chemin /old-station ne mène nulle part, mais l'équipage l'a toujours dans ses favoris. Ou bien un touriste non connecté essaie d'entrer dans le centre de contrôle. Dans les deux cas, on ne veut afficher ni page vide ni erreur. On veut que le vaisseau change de cap tout seul.

Dans l'espace interstellaire, nous avons parfois besoin de rediriger immédiatement notre vaisseau vers une autre trajectoire. Dans le monde de React Router, les redirections fonctionnent de manière similaire - elles nous permettent de transférer automatiquement l'utilisateur d'un chemin à un autre.

Les exemples de cette leçon fonctionnent de la même façon dans React Router v6 et v7. En v7, tu peux importer les mêmes composants et hooks depuis le paquet react-router, et react-router-dom les fournit toujours, donc les imports de cette leçon restent corrects. La version 8, sortie en juin 2026, ne contient plus le paquet react-router-dom : tu y importes les mêmes composants et hooks depuis react-router, et le code des exemples lui-même ne change pas.

Le composant Navigate

La façon la plus simple de créer une redirection est d'utiliser le composant Navigate de React Router :

1import { Navigate } from 'react-router-dom';
2
3function RedirectToControl() {
4  return <Navigate to="/control-center" />;
5}

Lorsque ce composant est rendu, l'utilisateur est automatiquement redirigé vers le chemin spécifié. C'est une manière déclarative de rediriger - il suffit de placer le composant dans l'arbre JSX.

Rediriger une ancienne route

Le scénario le plus simple, c'est une route qui a changé d'adresse. La configuration se fait en quatre étapes : tu définis la route source, tu lui donnes comme élément Navigate avec la nouvelle adresse, tu ajoutes replace, et React Router déplace l'utilisateur automatiquement :

1<Routes>
2  <Route path="/old-station" element={<Navigate to="/space-station" replace />} />
3  <Route path="/space-station" element={<SpaceStation />} />
4</Routes>

Celui qui tape l'ancienne adresse arrive sur /space-station, et aucune trace de l'ancien chemin ne reste dans l'historique du navigateur. Le composant SpaceStation ne sait rien de la redirection et n'a besoin d'aucune modification.

Les redirections conditionnelles

Il faut souvent rediriger l'utilisateur seulement dans certaines conditions, par exemple lorsqu'il n'est pas connecté. Le hook useAuth des exemples est notre propre hook (il ne fait pas partie de React Router) qui renvoie des informations sur l'utilisateur connecté :

1function SecretMoonBase() {
2  const isAstronaut = useAuth();
3
4  if (!isAstronaut) {
5    return <Navigate to="/access-denied" replace />;
6  }
7
8  return (
9    <div>
10      <h1>Base lunaire secrète</h1>
11      <p>Bienvenue astronaute ! Tu as accès aux données classifiées.</p>
12    </div>
13  );
14}

L'attribut replace fait en sorte que la redirection remplace la page actuelle dans l'historique du navigateur, au lieu d'en ajouter une nouvelle. Ainsi, l'utilisateur ne reviendra pas sur la page protégée après avoir cliqué sur le bouton "retour".

Les redirections programmatiques

Parfois, nous avons besoin de rediriger l'utilisateur en réponse à un événement, comme l'envoi d'un formulaire. Nous utilisons pour cela le hook useNavigate :

1import { useNavigate } from 'react-router-dom';
2
3function LaunchControlForm() {
4  const navigate = useNavigate();
5
6  const handleLaunch = (event) => {
7    event.preventDefault();
8    // Logique de préparation du lancement...
9
10    // Rediriger vers la page du compte à rebours
11    navigate('/countdown');
12
13    // Ou avec le paramètre replace
14    // navigate('/countdown', { replace: true });
15  };
16
17  return (
18    <form onSubmit={handleLaunch}>
19      <h2>Panneau de contrôle du lancement</h2>
20      <button type="submit">Démarrer le compte à rebours</button>
21    </form>
22  );
23}

On appelle la fonction navigate dans un gestionnaire d'événement, pas directement dans le corps du composant. React Router t'avertit si tu l'appelles pendant le premier rendu. Là où la décision se prend pendant le rendu, le composant Navigate convient mieux.

Ces deux outils sont les extrémités d'une même échelle. Du plus déclaratif au plus impératif : Link (un simple lien en JSX), NavLink (un lien avec un état actif), Navigate (une redirection en JSX) et useNavigate (un hook appelé dans le code).

Gérer les chemins inexistants (404)

React Router nous permet de gérer facilement le cas où un utilisateur tente d'accéder à un chemin qui n'existe pas :

1<Routes>
2  <Route path="/mission-control" element={<MissionControl />} />
3  <Route path="/navigation" element={<Navigation />} />
4  <Route path="*" element={<Navigate to="/lost-in-space" />} />
5</Routes>

Le chemin * correspond à n'importe quelle route qui ne correspond à aucune des précédentes. Au lieu de Navigate, nous pouvons aussi rendre un composant 404 :

1<Route path="*" element={<LostInSpace />} />

Je te recommande la seconde option. Une page « perdu dans l'espace » garde l'URL erronée dans la barre d'adresse, donc l'utilisateur voit ce qu'il a tapé et peut le corriger.

Les redirections avec paramètres

On peut aussi transmettre des données supplémentaires lors d'une redirection. C'est le rôle de l'option state, disponible aussi bien dans le composant que dans la fonction navigate :

1// Redirection déclarative avec paramètres
2<Navigate
3  to="/asteroid-alert"
4  state={{ severity: "high", location: "sector-7" }}
5/>
6
7// Redirection programmatique avec paramètres
8navigate('/asteroid-alert', {
9  state: { severity: "high", location: "sector-7" }
10});

Les données de state ne vont pas dans l'URL, donc l'adresse reste propre. Dans le composant cible, nous pouvons lire ces données à l'aide du hook useLocation :

1import { useLocation } from 'react-router-dom';
2
3function AsteroidAlert() {
4  const location = useLocation();
5  const { severity, location: asteroidLocation } = location.state || {};
6
7  return (
8    <div className="alert">
9      <h1>Alerte astéroïde !</h1>
10      {severity && asteroidLocation && (
11        <p>
12          Astéroïde détecté avec un niveau de menace {severity} à l'emplacement {asteroidLocation}.
13        </p>
14      )}
15    </div>
16  );
17}

Remarque le location.state || {}. Si quelqu'un ouvre la page directement depuis la barre d'adresse, state sera vide, et cette protection évite une erreur dans le composant.

Les redirections avec authentification

Le cas d'usage le plus courant des redirections est la protection des routes contre les utilisateurs non autorisés. Le composant ProtectedRoute lit l'emplacement actuel avec le hook useLocation pour mémoriser où l'utilisateur voulait aller :

1function ProtectedRoute({ children }) {
2  const { user, loading } = useAuth();
3  const location = useLocation();
4
5  if (loading) {
6    return <LoadingSpinner />;
7  }
8
9  if (!user) {
10    // Rediriger vers la page de connexion en enregistrant le chemin d'origine
11    return <Navigate to="/login" state={{ from: location.pathname }} />;
12  }
13
14  return children;
15}
16
17// Utilisation :
18<Routes>
19  <Route path="/mission-control" element={
20    <ProtectedRoute>
21      <MissionControl />
22    </ProtectedRoute>
23  } />
24</Routes>

Le composant protégé MissionControl reste inchangé, c'est l'enveloppe qui contient toute la logique d'accès. Sur la page de connexion, nous pouvons lire le chemin d'origine et rediriger l'utilisateur après la connexion :

1function Login() {
2  const navigate = useNavigate();
3  const location = useLocation();
4  const from = location.state?.from || '/dashboard';
5
6  const handleLogin = async (credentials) => {
7    const success = await loginUser(credentials);
8
9    if (success) {
10      // Rediriger vers la page d'origine
11      navigate(from, { replace: true });
12    }
13  };
14
15  // Reste du composant...
16}

Ici, replace: true retire la page de connexion de l'historique, donc le bouton « retour » ne ramènera pas l'astronaute connecté au formulaire.

En mode données de React Router (depuis la v6.4, et aussi en v7), les redirections se font souvent dès les fonctions loader et action grâce à la fonction redirect, avant même le rendu du composant. Tu découvriras cela avec une architecture de routage plus avancée.

Résumé

Les redirections sont un outil puissant dans les applications React utilisant React Router. Elles permettent de :

  1. Déplacer automatiquement les utilisateurs entre les chemins
  2. Créer des zones protégées nécessitant une authentification
  3. Gérer les chemins inexistants (404)
  4. Passer des données entre les pages lors d'une redirection

N'oublie pas d'utiliser le paramètre replace lorsque tu veux empêcher l'utilisateur de revenir à la page précédente à l'aide du bouton "retour" - c'est particulièrement important dans le cas des pages de connexion et d'autres scénarios d'authentification.

Tu as déjà rencontré la protection des routes dans la leçon précédente, et dans la suivante tu verras comment le lazy loading charge les modules du vaisseau seulement quand ils sont nécessaires.

Retiens : Navigate change de cap pendant le rendu, useNavigate après un événement, et replace efface les traces dans le journal de bord.

Code de cette leçon : App.jsx
1import React from 'react';
2import { BrowserRouter, Routes, Route, Link, Outlet, useParams } from 'react-router-dom';
3
4// Mise en page pour la section Fleet
5function FleetLayout() {
6  return (
7    <div className="fleet-layout">
8      <aside className="fleet-nav">
9        <h2>Flotte</h2>
10        <Link to="/fleet/alpha">Escadron Alpha</Link>
11        <Link to="/fleet/beta">Escadron Beta</Link>
12        <Link to="/fleet/gamma">Escadron Gamma</Link>
13      </aside>
14      <main className="fleet-content">
15        {/* Outlet rend les routes imbriquées */}
16        <Outlet />
17      </main>
18    </div>
19  );
20}
21
22// Page d'accueil de la flotte
23function FleetHome() {
24  return (
25    <div className="page">
26      <h1>Choisis un escadron</h1>
27      <p>Clique sur un escadron dans le menu pour voir les détails.</p>
28    </div>
29  );
30}
31
32// Détails de l'escadron
33function SquadronDetails() {
34  const { squadronId } = useParams();
35
36  return (
37    <div className="page squadron">
38      <h1>Escadron : {squadronId?.toUpperCase()}</h1>
39
40      <div className="squadron-nav">
41        <Link to={`/fleet/${squadronId}/ships`}>Vaisseaux</Link>
42        <Link to={`/fleet/${squadronId}/crew`}>Équipage</Link>
43        <Link to={`/fleet/${squadronId}/missions`}>Missions</Link>
44      </div>
45
46      {/* Un autre Outlet pour les routes imbriquées plus profondes */}
47      <Outlet />
48    </div>
49  );
50}
51
52// Composants imbriqués pour l'escadron
53function SquadronShips() {
54  const { squadronId } = useParams();
55  return (
56    <div className="sub-page">
57      <h2>Vaisseaux de l'escadron {squadronId}</h2>
58      <ul>
59        <li>Fighter-01</li>
60        <li>Fighter-02</li>
61        <li>Cruiser-01</li>
62      </ul>
63    </div>
64  );
65}
66
67function SquadronCrew() {
68  const { squadronId } = useParams();
69  return (
70    <div className="sub-page">
71      <h2>Équipage de l'escadron {squadronId}</h2>
72      <ul>
73        <li>Capitaine : John Smith</li>
74        <li>Pilote : Anna Kowalska</li>
75        <li>Ingénieur : Mark Johnson</li>
76      </ul>
77    </div>
78  );
79}
80
81function SquadronMissions() {
82  const { squadronId } = useParams();
83  return (
84    <div className="sub-page">
85      <h2>Missions de l'escadron {squadronId}</h2>
86      <ul>
87        <li>Patrouille du secteur 7 - En cours</li>
88        <li>Escorte de transport - Terminée</li>
89      </ul>
90    </div>
91  );
92}
93
94function App() {
95  return (
96    <BrowserRouter>
97      <div className="app">
98        <header>
99          <Link to="/">Accueil</Link>
100          <Link to="/fleet">Flotte</Link>
101        </header>
102
103        <Routes>
104          <Route path="/" element={<div className="page home"><h1>Space Command</h1></div>} />
105
106          {/* Routes imbriquées */}
107          <Route path="/fleet" element={<FleetLayout />}>
108            <Route index element={<FleetHome />} />
109            <Route path=":squadronId" element={<SquadronDetails />}>
110              <Route path="ships" element={<SquadronShips />} />
111              <Route path="crew" element={<SquadronCrew />} />
112              <Route path="missions" element={<SquadronMissions />} />
113            </Route>
114          </Route>
115        </Routes>
116      </div>
117    </BrowserRouter>
118  );
119}
120
121export default App;

Tu as repéré une erreur dans cette leçon ?

Tâches pratiques dans le jeu

  • Tri vertical

    Ordonne les étapes de configuration d'une redirection dans React Router v6 :

  • Tri vertical

    Ordonne le processus de rendu d'une route imbriquée dans React Router :

  • Éditeur de code

    Chargement dynamique de données avec params

  • Clique dans l'ordre

    Ordonne le code de navigation programmatique après la connexion :

  • Tri vertical

    Ordonne les méthodes de navigation de React Router, du déclaratif à l'impératif :

Articles utiles