Cours JavaScript et React · Module 6: React Router

Configuration du routage dans les applications spatiales

8 min de lecture
Dans cette leçon8

Dans le module précédent, nous avons appris les bases de React Router en tant que système de navigation interplanétaire. Maintenant, nous allons plonger plus profondément dans les détails de la configuration du routage dans différents types d'applications spatiales, qu'il s'agisse de petites applications ou de systèmes multi-modules complexes.

Les différents types de routeurs dans React Router

React Router propose plusieurs types de routeurs que nous pouvons utiliser selon l'environnement dans lequel notre application s'exécute :

1. BrowserRouter

BrowserRouter utilise l'API History de HTML5 et est le routeur le plus couramment utilisé dans les applications web modernes. Il crée des URL propres et élégantes, sans hash (#) :

1import { BrowserRouter } from 'react-router-dom';
2
3function App() {
4  return (
5    <BrowserRouter>
6      {/* Composants de routage */}
7    </BrowserRouter>
8  );
9}

Important : BrowserRouter nécessite une configuration serveur appropriée qui doit rediriger toutes les requêtes vers le fichier index.html (pour gérer le rafraîchissement de la page et l'accès direct aux sous-pages).

2. HashRouter

HashRouter utilise la fonction de hash dans l'URL (la partie après #). C'est une solution plus simple qui ne nécessite pas de configuration serveur, mais qui crée des URL moins élégantes :

1import { HashRouter } from 'react-router-dom';
2
3function App() {
4  return (
5    <HashRouter>
6      {/* Composants de routage */}
7    </HashRouter>
8  );
9}

Exemples d'URL avec HashRouter : /#/mars, /#/jupiter

3. MemoryRouter

MemoryRouter stocke l'historique de navigation en mémoire (il n'utilise pas l'URL du navigateur). Il est utile pour les tests et les applications s'exécutant dans des environnements sans navigateur :

1import { MemoryRouter } from 'react-router-dom';
2
3function App() {
4  return (
5    <MemoryRouter initialEntries={['/mars', '/jupiter']} initialIndex={1}>
6      {/* Composants de routage */}
7    </MemoryRouter>
8  );
9}

Configuration avancée des routes

Le composant Route offre plus d'options que le simple mappage chemin-vers-élément :

1. Chemins dynamiques avec paramètres

1<Route path="/planet/:planetId" element={<PlanetDetails />} />

Ce chemin correspond à des URL comme /planet/mars, /planet/jupiter, etc. Le paramètre :planetId est dynamique et peut être lu dans le composant.

2. Chemins optionnels

1<Route path="/missions/:year?/:month?" element={<MissionsList />} />

Les points d'interrogation indiquent des paramètres optionnels. Ce chemin correspond aux URL :

  • /missions (sans paramètres)
  • /missions/2150 (année uniquement)
  • /missions/2150/06 (année et mois)

3. Paramètres génériques (catch-all)

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

L'astérisque capture tout ce qui suit /files/, par ex. /files/documents/reports/annual.pdf.

Structure de routage pour les applications spatiales plus grandes

Dans les applications spatiales étendues, le routage peut devenir complexe. Voici comment tu peux l'organiser :

1. Routes imbriquées

Nous pouvons imbriquer des routes pour créer une structure hiérarchique :

1function AppRoutes() {
2  return (
3    <Routes>
4      <Route path="/" element={<SpaceLayout />}>
5        <Route index element={<Dashboard />} />
6        <Route path="planets" element={<PlanetLayout />}>
7          <Route index element={<PlanetsList />} />
8          <Route path=":planetId" element={<PlanetDetails />} />
9        </Route>
10        <Route path="missions" element={<MissionLayout />}>
11          <Route index element={<MissionsDashboard />} />
12          <Route path="scheduled" element={<ScheduledMissions />} />
13          <Route path="completed" element={<CompletedMissions />} />
14        </Route>
15      </Route>
16      <Route path="/auth" element={<AuthLayout />}>
17        <Route path="login" element={<Login />} />
18        <Route path="register" element={<Register />} />
19      </Route>
20      <Route path="*" element={<NotFound />} />
21    </Routes>
22  );
23}

Dans l'exemple ci-dessus :

  • SpaceLayout est la mise en page principale pour les chemins commençant par "/"
  • PlanetLayout est la mise en page pour tous les chemins de la section "planets"
  • L'élément index indique ce qui doit être rendu pour le chemin parent (par ex. "/planets")

2. Route element vs. component

Depuis React Router v6, on utilise la prop element au lieu de component des versions précédentes :

1// React Router v6 et versions suivantes (v7, v8)
2<Route path="/mars" element={<MarsBase />} />
3
4// React Router v5 (plus ancien)
5<Route path="/mars" component={MarsBase} />

Pourquoi est-ce important ? La syntaxe element permet de passer un élément déjà rendu, ce qui offre une plus grande flexibilité :

1<Route
2  path="/mars"
3  element={
4    <MarsBase
5      temperature={-60}
6      oxygenLevel="low"
7      waterAvailable={true}
8    />
9  }
10/>

3. Outlet - Afficher les composants des sous-routes

Le composant Outlet indique où, dans le composant parent, les composants des sous-routes doivent être rendus :

1import { Outlet } from 'react-router-dom';
2
3function SpaceLayout() {
4  return (
5    <div className="space-layout">
6      <header>
7        <h1>Système de navigation interplanétaire</h1>
8        <nav>{/* Liens de navigation */}</nav>
9      </header>
10
11      <main>
12        {/* Les composants des sous-routes seront rendus ici */}
13        <Outlet />
14      </main>
15
16      <footer>
17        <p>Centre de commandement spatial &copy; 2150</p>
18      </footer>
19    </div>
20  );
21}

Configuration avec gestion des erreurs

Une bonne pratique consiste à ajouter une gestion globale des erreurs à notre système de routage :

1function AppRoutes() {
2  return (
3    <Routes>
4      <Route path="/" element={<SpaceLayout />} errorElement={<GlobalError />}>
5        {/* Autres routes */}
6      </Route>
7    </Routes>
8  );
9}
10
11function GlobalError() {
12  const error = useRouteError();
13
14  return (
15    <div className="error-container">
16      <h1>Houston, nous avons un problème !</h1>
17      <p>Une erreur est survenue dans le système de navigation :</p>
18      <pre>{error.message || "Erreur inconnue"}</pre>
19      <button onClick={() => window.location.href = "/"}>
20        Retour au centre de commandement
21      </button>
22    </div>
23  );
24}

Exemple de configuration complète pour une application spatiale complexe

Voici un exemple complet de configuration du routage pour une application avancée :

1import {
2  BrowserRouter,
3  Routes,
4  Route,
5  Outlet,
6  Navigate,
7  useRouteError
8} from 'react-router-dom';
9
10// Mises en page
11function MainLayout() {
12  return (
13    <div className="main-layout">
14      <MainNavigation />
15      <div className="content">
16        <Outlet />
17      </div>
18      <Footer />
19    </div>
20  );
21}
22
23function AuthLayout() {
24  return (
25    <div className="auth-layout">
26      <div className="auth-container">
27        <Outlet />
28      </div>
29    </div>
30  );
31}
32
33// Composants d'erreur
34function GlobalError() {
35  const error = useRouteError();
36  return (
37    <div className="error-screen">
38      <h1>Erreur du système de navigation</h1>
39      <p>{error.message || "Erreur inconnue"}</p>
40    </div>
41  );
42}
43
44function NotFound() {
45  return (
46    <div className="not-found">
47      <h1>Perdu dans l'espace lointain</h1>
48      <p>Le vaisseau n'a pas pu trouver l'emplacement demandé.</p>
49    </div>
50  );
51}
52
53// Composant de route protégée
54function ProtectedRoute({ children }) {
55  const isAuthenticated = useAuth();
56
57  if (!isAuthenticated) {
58    return <Navigate to="/auth/login" replace />;
59  }
60
61  return children;
62}
63
64// Application principale
65function App() {
66  return (
67    <BrowserRouter>
68      <Routes>
69        {/* Section principale avec mise en page */}
70        <Route path="/" element={<MainLayout />} errorElement={<GlobalError />}>
71          <Route index element={<Dashboard />} />
72
73          {/* Planètes */}
74          <Route path="planets">
75            <Route index element={<PlanetsList />} />
76            <Route path=":planetId" element={<PlanetDetails />} />
77          </Route>
78
79          {/* Missions - nécessitent une authentification */}
80          <Route path="missions" element={
81            <ProtectedRoute>
82              <MissionsLayout />
83            </ProtectedRoute>
84          }>
85            <Route index element={<MissionsDashboard />} />
86            <Route path="new" element={<NewMission />} />
87            <Route path=":missionId" element={<MissionDetails />} />
88            <Route path=":missionId/edit" element={<EditMission />} />
89          </Route>
90
91          {/* Équipage */}
92          <Route path="crew">
93            <Route index element={<CrewList />} />
94            <Route path=":memberId" element={<CrewMemberProfile />} />
95          </Route>
96
97          {/* Paramètres - nécessitent une authentification */}
98          <Route path="settings" element={
99            <ProtectedRoute>
100              <Settings />
101            </ProtectedRoute>
102          } />
103        </Route>
104
105        {/* Section d'authentification */}
106        <Route path="/auth" element={<AuthLayout />}>
107          <Route path="login" element={<Login />} />
108          <Route path="register" element={<Register />} />
109          <Route path="forgot-password" element={<ForgotPassword />} />
110          <Route path="reset-password/:token" element={<ResetPassword />} />
111        </Route>
112
113        {/* Documentation publique */}
114        <Route path="/docs/*" element={<DocsLayout />} />
115
116        {/* Redirection de l'ancien chemin vers le nouveau */}
117        <Route path="/old-missions" element={<Navigate to="/missions" replace />} />
118
119        {/* Gestion du 404 */}
120        <Route path="*" element={<NotFound />} />
121      </Routes>
122    </BrowserRouter>
123  );
124}

Configuration de React Router en environnement de développement

Lors du développement d'une application spatiale, il vaut la peine de configurer les outils de développement pour qu'ils fonctionnent avec React Router :

1. React Router DevTools

1// Uniquement en mode développement
2if (process.env.NODE_ENV === 'development') {
3  const ReactRouterDevTools = React.lazy(() =>
4    import('react-router-devtools').then(module => ({
5      default: module.ReactRouterDevTools
6    }))
7  );
8
9  // Utilisation dans l'application
10  <React.Suspense fallback={null}>
11    <ReactRouterDevTools />
12  </React.Suspense>
13}

2. Configuration de webpack-dev-server pour BrowserRouter

Pour gérer le rafraîchissement de la page en environnement de développement avec BrowserRouter, il faut configurer webpack-dev-server :

1// webpack.config.js
2module.exports = {
3  // autres paramètres...
4  devServer: {
5    historyApiFallback: true, // Rediriger les 404 vers index.html
6    // autres paramètres...
7  }
8};

Configuration du serveur de production pour React Router

En environnement de production, le serveur doit être configuré pour gérer tous les chemins de React Router :

1. Pour un serveur Node.js/Express :

1const express = require('express');
2const path = require('path');
3const app = express();
4
5// Servir les fichiers statiques
6app.use(express.static(path.join(__dirname, 'build')));
7
8// Toutes les requêtes qui ne concernent pas des fichiers statiques sont redirigées vers index.html
9app.get('*', (req, res) => {
10  res.sendFile(path.join(__dirname, 'build', 'index.html'));
11});
12
13const PORT = process.env.PORT || 3000;
14app.listen(PORT, () => {
15  console.log(`Serveur à l'écoute sur le port ${PORT}`);
16});

2. Pour un serveur Apache (.htaccess) :

1<IfModule mod_rewrite.c>
2  RewriteEngine On
3  RewriteBase /
4  RewriteRule ^index\.html$ - [L]
5  RewriteCond %{REQUEST_FILENAME} !-f
6  RewriteCond %{REQUEST_FILENAME} !-d
7  RewriteRule . /index.html [L]
8</IfModule>

3. Pour un serveur Nginx :

1server {
2  listen 80;
3  server_name space-application.com;
4
5  root /var/www/html;
6  index index.html;
7
8  location / {
9    try_files $uri $uri/ /index.html;
10  }
11}

Résumé

Une configuration correcte du routage est cruciale pour le bon fonctionnement d'une application spatiale (React). Points clés :

  1. Choisis le bon type de routeur - généralement BrowserRouter pour les applications modernes
  2. Crée des structures de routes hiérarchiques - utilise des routes imbriquées avec Outlet pour une meilleure organisation
  3. Implémente la gestion des erreurs - utilise errorElement pour gérer les erreurs
  4. Sécurise les routes privées - crée un composant ProtectedRoute pour protéger l'accès
  5. Configure le serveur de production - assure-toi que le serveur redirige toutes les requêtes vers index.html

Avec un système de navigation bien configuré, les utilisateurs de ton application spatiale pourront voyager librement entre ses différentes parties, sans craindre de se perdre dans l'espace lointain (erreurs 404).

Code de cette leçon : App.jsx
1import React from 'react';
2import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
3
4// Page d'accueil
5function Home() {
6  return (
7    <div className="page home">
8      <h1>Page d'accueil</h1>
9      <p>Bienvenue dans le centre de navigation cosmique !</p>
10      <p>Utilise le menu ci-dessus pour naviguer entre les pages.</p>
11    </div>
12  );
13}
14
15// Page "À propos"
16function About() {
17  return (
18    <div className="page about">
19      <h1>À propos</h1>
20      <p>Nous sommes une équipe d'explorateurs de l'espace.</p>
21      <p>Notre mission : explorer la galaxie grâce à React Router !</p>
22    </div>
23  );
24}
25
26// Page de contact
27function Contact() {
28  return (
29    <div className="page contact">
30      <h1>Contact</h1>
31      <p>Email : mission-control@space.com</p>
32      <p>Téléphone : +48 123 456 789</p>
33    </div>
34  );
35}
36
37// Navigation
38function Navigation() {
39  return (
40    <nav className="navigation">
41      <Link to="/" className="nav-link">Accueil</Link>
42      <Link to="/about" className="nav-link">À propos</Link>
43      <Link to="/contact" className="nav-link">Contact</Link>
44    </nav>
45  );
46}
47
48function App() {
49  return (
50    <BrowserRouter>
51      <div className="app">
52        <header>
53          <h2>Space Navigator</h2>
54          <Navigation />
55        </header>
56
57        <main>
58          <Routes>
59            <Route path="/" element={<Home />} />
60            <Route path="/about" element={<About />} />
61            <Route path="/contact" element={<Contact />} />
62          </Routes>
63        </main>
64      </div>
65    </BrowserRouter>
66  );
67}
68
69export default App;

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

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Quelle est la principale différence entre BrowserRouter et HashRouter ?

Tâches pratiques dans le jeu

  • Clique dans l'ordre

    Ordonne la commande d'installation de React Router :

  • Éditeur de code

    Crée : <BrowserRouter><Routes><Route path='/' element={<Dashboard />} /><Route path='/planets' element={<Planets />} /><Route path='/missions' element={<Missions />} /></Routes></BrowserRouter>. Ajoute <Link to='/planets'>Planets</Link> !

  • Clique dans l'ordre

    Ordonne la structure de base d'une application React Router :

  • Éditeur de code

    Crée la navigation : <nav><NavLink to='/' className={({isActive}) => isActive ? 'active' : ''}>Home</NavLink><NavLink to='/asteroids'>Asteroids</NavLink></nav>. Ajoute le CSS : .active { color: gold; border-bottom: 2px solid gold }

Articles utiles