
Prenons notre machine à voyager dans le temps et retournons aux débuts du Web.
À cette époque, l'immense majorité des sites consistaient en un groupe de pages, envoyées par le serveur, qui s'affichaient en fonction de la navigation. Pour chaque interaction, telle que l'envoi d'un formulaire, la page entière devait être rechargée.
Mais au début des années 2000, le concept de Single Page Application (SPA) commence à émerger. Les idées principales derrière ce concept sont les suivantes :
Les utilisateurs ne chargent une page Web qu'une seule fois (le fameux index.html).
Au lieu de récupérer toute la page avec une requête HTTP, on les récupère de manière distincte, petite partie par petite partie, ce qui permet à l'utilisateur d'interagir de manière beaucoup plus dynamique.
L'utilisateur peut naviguer entre plusieurs pages et JavaScript (et dans notre cas, React) gère l'affichage de nouvelles pages au sein du même domaine, sans qu'un rafraîchissement complet de la page soit nécessaire.

Dans une application classique, chaque clic sur un lien déclenche une nouvelle requête au serveur qui renvoie une page HTML complète. Avec une SPA, le serveur envoie une seule fois l'application, puis JavaScript gère toutes les interactions et la navigation côté client. L'application communique avec le serveur uniquement pour récupérer ou envoyer des données, généralement au format JSON.
Mais est-ce que cela veut dire que les SPA sont forcément meilleures ? Et que tous les nouveaux sites sont développés comme des SPA ?
Eh bien, non. Toutes les applications ne sont pas des SPA.
Développer un site en Single Page Application présente aussi des inconvénients. Par exemple, les utilisateurs doivent obligatoirement avoir JavaScript activé pour que le site fonctionne correctement. De plus, le référencement (SEO, c’est-à-dire l’indexation du site par les moteurs de recherche) est généralement plus complexe pour les applications monopages.
Pour notre application, nous allons créer une vraie Single Page Application avec React Router pour Shiny, une agence de développement web. Le dashboard de Shiny permettra de visualiser des informations sur les employés et les projets de l'agence.
Les projets que nous créons avec Vite et React ne peuvent pas encore être considérés comme des Single Page Applications : il leur manque une solution de routing.
Du routing ? Très bien, mais concrètement, ça veut dire quoi une route ?
Contrairement aux frameworks comme Angular, React ne nous fournit pas directement une solution pour gérer les routes de notre application. Pas de panique, comme pour quasiment tout en React, l'écosystème a vite comblé ce besoin. Il existe donc plusieurs solutions de routing. Celle à laquelle nous allons nous intéresser dans ce cours est React Router (le nom est plutôt bien trouvé, n'est-ce pas ? 🙃).
Comme nous pouvons le voir dans la documentation React Router, une route permet d'afficher des composants de manière conditionnelle si le path (chemin) de l'URL correspond au path de la route.
On lui passe en prop le path auquel la route correspond et elle se charge d'afficher l'element qui lui est passé.
Cette bibliothèque, créée par Remix, met à votre disposition tous les outils nécessaires pour gérer la navigation dans votre application côté client.
Alors, partons à la découverte de React Router.
Avant de commencer, assurez-vous d'avoir téléchargé l'application de base Shiny fournie avec ce cours. Elle contient déjà :
Une application Vite avec React 19 configurée
Toutes les pages déjà créées et stylisées (Home, Projects, Employees, About, Error)
Un Header avec navigation
Des données mockées pour les employés et les projets
Des composants réutilisables (ProjectCard, EmployeeCard)
Lancez l'application avec npm run dev et ouvrez http://localhost:5174 dans votre navigateur. Vous verrez le dashboard de Shiny avec un header contenant trois liens : Dashboard, Projets et Employés.
Cliquez sur ces liens. Que se passe-t-il ? La page scrolle vers différentes sections, mais l'URL change seulement avec des ancres (#dashboard, #projects, #employees). Ce n'est pas encore une vraie Single Page Application : nous n'avons qu'une seule page qui scrolle !

Nous allons installer la bibliothèque pour transformer cette application en vraie SPA avec :
npm install react-router-dom
Cette commande installera automatiquement la dernière version stable de React Router (actuellement la v7).
React Router est maintenant prêt à être utilisé !
Votre mission, si vous l'acceptez, est de pouvoir naviguer entre les différentes pages de Shiny : Dashboard (Home), Projects, Employees et About.
Nous allons utiliser React Router et ses composants BrowserRouter, Routes et Route.
Dans l’exemple ci-dessous, dans le fichier main.jsx, on importe le composant BrowserRouter depuis React Router et on le renomme enRouterpour simplifier la lecture du code.
Router est ensuite utilisé comme composant racine de l’application. Il permet à React Router de suivre l’URL courante (celle affichée dans la barre d’adresse du navigateur) et de réagir à ses changements afin d’afficher la bonne page.
Ensuite, nous ajoutons le composant Routes qui va servir à sélectionner le composant enfant correspondant à la location.
Enfin, le composant le plus complexe, le composant Route. Ce composant prend de base plusieurs paramètres dont à minima :
path qui contient l'URL dans notre navigateur qui dirigera vers le composant ;
element qui va permettre de sélectionner le composant à afficher.
Le fichier main.jsx à la racine de notre projet se transforme donc de cette manière :
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import Header from './components/Header'
import Home from './pages/Home'
import Projects from './pages/Projects'
import Employees from './pages/Employees'
import About from './pages/About'
import Error from './pages/Error'
import './index.css'
createRoot(document.getElementById('root')).render(
<StrictMode>
<Router>
<Header />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/projects" element={<Projects />} />
<Route path="/employees" element={<Employees />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<Error />} />
</Routes>
</Router>
</StrictMode>
)
L'idée est maintenant de mettre dans notre router toutes les routes qui seront accessibles. Il faudra afficher le bon composant pour chaque URL.
Yay ! Si vous allez sur l'URL http://localhost:5174/, on a bien la page d'accueil (notre dashboard) qui s'affiche. C'est la même chose si vous tapez http://localhost:5174/projects dans la barre d'URL : la page Projects s'affiche !
Félicitations ! Tout fonctionne bien comme prévu !
Mais bon… Ce n'est pas vraiment pratique de devoir taper toutes nos URL à la main dans la barre du navigateur pour changer de page.
Et si vous regardez bien, notre Header contient toujours des balises <a href="#..."> qui font scroller la page au lieu de naviguer entre les pages.
Modifions notre Header pour utiliser les composants React Router !
Ouvrez le fichier /components/Header/index.jsx. Vous verrez qu'il contient actuellement des balises <a> avec des ancres :
<a href="#dashboard" classname="nav-link">Dashboard</a>
<a href="#projects" classname="nav-link">Projets</a>
<a href="#employees" classname="nav-link">Employés</a>Nous allons les remplacer par des composants Link de React Router. Voici le code modifié :
import { Link } from 'react-router-dom'
import './Header.css'
function Header() {
return (
<header className="header">
<div className="header-content">
<h1 className="header-logo">Shiny</h1>
<nav className="nav">
<Link to="/" className="nav-link">Dashboard</Link>
<Link to="/projects" className="nav-link">Projets</Link>
<Link to="/employees" className="nav-link">Employés</Link>
</nav>
</div>
</header>
)
}
export default Header
Les changements sont simples :
Nous importons Link depuis react-router-dom
Nous remplaçons les <a href="#..."> par des <Link to="...">
Le to indique le path de la route à afficher (comme défini dans main.jsx)
Ici, j’utilise le composantLink, fourni par React Router, qui se comporte comme une balise<a>classique. Il est donc important de l’utiliser pour la navigation afin de respecter les bonnes pratiques d’accessibilité, plutôt que de déclencher des redirections via des gestionnairesonClick.
Vous avez maintenant une vraie Single Page Application avec navigation : félicitations à vous, vous avez fait du bon boulot.
Testez maintenant dans votre navigateur : vous pouvez cliquer sur les liens "Dashboard", "Projets" et "Employés" et observer que la page ne se recharge pas complètement. Seul le contenu change ! L'URL change également (/, /projects, /employees) mais sans rechargement. C'est exactement le comportement d'une Single Page Application.
Quelle chance, tout fonctionne comme on le souhaite ! Mais qu'est-ce qui se passe si je commence à taper n'importe quoi dans mon URL ? Par exemple, si j'essaie d'accéder au contenu dehttp://localhost:5174/pagequinexistepas ?
Notre header s'affiche, mais rien d'autre… Moi, j'aimerais signaler à l'utilisateur que rien n'existe à cette adresse. Eh bien, ça vous dit quelque chose, les pages d'erreur ? C'est ce que nous allons faire ici : afficher une page 404.
Bonne nouvelle : le composant Error existe déjà danssrc/pages/Error/index.jsx ! Regardons son code :
import './Error.css'
import {Link} from "react-router-dom";
function Error() {
return (
<div className="page">
<div className="error-container">
<h1 className="error-title">404</h1>
<h2>Oups 🙈 Cette page n'existe pas</h2>
<p>La page que vous cherchez semble introuvable.</p>
<Link to="/" className="error-link">
Retour à l'accueil
</Link>
</div>
</div>
)
}
export default Error
Le composant existe déjà, mais il n'est pas encore utilisé dans notre router. Si vous regardez le fichier main.jsx que nous avons modifié plus tôt, vous verrez que nous avons déjà ajouté cette ligne :
<Route path="*" element={<Error />} />Afin de gérer les erreurs pour les routes qui n'existent pas, nous avons ajouté une route avec un path particulier, le path="*". Ainsi, toutes les routes qui ne sont pas mentionnées plus haut conduiront à notre page d'erreur.

Yes !
Testez-le dans votre navigateur en tapant n'importe quelle URL invalide. La page d'erreur s'affiche correctement !

Vous avez la base de votre application, félicitations à vous. C'est maintenant le moment de voler de vos propres ailes.
L'application Shiny contient déjà toutes les pages, mais pour l'instant, le lien "À propos" n'est pas accessible depuis le Header. Votre mission est de l'ajouter !
Le code pour debuter l’exercice est disponible sur la branche P1C2-Begin
Vos objectifs :
Modifier le Header
Ouvrez src/components/Header/index.jsx
Ajoutez un quatrième lien <Link> pointant vers /about avec le texte "À propos".
Tester la navigation
Vérifiez que vous pouvez naviguer entre toutes les pages (Dashboard, Projets, Employés, À propos).
Vérifiez que la page 404 s'affiche pour une URL invalide (par exemple,/test).
Observez qu'il n'y a aucun rechargement de page lors de la navigation.
L'URL change bien dans la barre d'adresse.
Bonus : Personnaliser la page About
Modifiez le contenu desrc/pages/About/index.jsx
Ajoutez des informations sur Shiny.
Consultez les données dans src/data/employees.js et src/data/projects.jspour vous inspirer.
La solution se trouve dans la branche P1C2-Solution.
Avec les Single Page Applications (SPA), l'utilisateur a l'impression de naviguer sur différentes pages, mais il n'existe qu'une seule page HTML sur laquelle le contenu est greffé avec JavaScript.
React Router est l'une des bibliothèques qui permettent de transformer une app React en SPA.
Les composants BrowserRouter, Routes et Route permettent de gérer l'affichage des différentes pages.
Le composant Link permet de naviguer entre les pages sans rechargement complet, préservant ainsi l'expérience SPA.
En indiquant une route avec path="*" à la fin des routes, cela permet de capturer toutes les routes dont le path ne correspond à aucune route déclarée, et donc de créer une page 404.
Notre application Shiny contient maintenant les bases d'une vraie Single Page Application ! Au prochain chapitre, nous allons découvrir comment créer des routes avec des paramètres dynamiques, ce qui nous permettra d'afficher les détails d'un employé spécifique avec useParams. Alors, rendez-vous au prochain chapitre !