React Router

Navigation côté client dans les SPA

Utilisez les flèches, cliquez ou glissez pour naviguer

Objectifs de la leçon

1. Installer React Router

npm install react-router-dom

2. Créer des routes

BrowserRouter, Routes, Route

3. Naviguer sans rechargement

Link et NavLink

4. Paramètres dynamiques

useParams pour :id

5. Routes imbriquées

Outlet

6. Routes protégées

Redirection

7. Query params

useSearchParams

Plan du cours

1

Le problème des SPA

Une seule page HTML, comment gérer plusieurs "pages" ?

2

React Router

Installation et configuration de base

3

Demo live : 3 pages

Home, About, Contact avec navigation

4

Routes dynamiques

useParams pour les pages produit/:id

5

Routes protégées

Redirection si non connecté

Le problème des SPA

Une SPA = une seule page HTML

Sites traditionnels (MPA)

  • Chaque page = un fichier HTML
  • Navigation = rechargement complet
  • Le serveur envoie une nouvelle page

Single Page Application

  • Un seul fichier HTML
  • JavaScript change le contenu
  • Pas de rechargement de page

Comment gérer plusieurs "pages" sans recharger ?

Solution : React Router simule la navigation côté client

React Router

Le routeur standard de l'écosystème React

Gère l'URL et affiche le composant correspondant

Sans rechargement de page !

Installation

npm install react-router-dom

react-router-dom est le package pour les applications web

Il existe aussi react-router-native pour React Native

// Vérifier la version installée

npm list react-router-dom

BrowserRouter

Le composant qui enveloppe toute l'application

Il utilise l'API History du navigateur pour gérer l'URL

// main.jsx ou App.jsx

import { BrowserRouter } from 'react-router-dom';

<BrowserRouter>

<App />

</BrowserRouter>

Oublier BrowserRouter = les routes ne fonctionnent pas !

Routes et Route

Routes

Conteneur pour toutes les routes

Remplace l'ancien Switch

Route

Définit une seule route

path + element

<Routes>

<Route path="/" element={<Home />} />

<Route path="/about" element={<About />} />

</Routes>

L'URL change le composant affiché automatiquement

Demo : Setup basique 3 pages

// App.jsx

import { BrowserRouter, Routes, Route } from 'react-router-dom';

import Home from './pages/Home';

import About from './pages/About';

import Contact from './pages/Contact';

function App() {

return (

<BrowserRouter>

<Routes>

<Route path="/" element={<Home />} />

<Route path="/about" element={<About />} />

<Route path="/contact" element={<Contact />} />

</Routes>

</BrowserRouter>

);

}

3 pages, 3 composants, 1 fichier HTML

Link vs <a>

Navigation sans rechargement

<a href>

Recharge la page

Pert tout le state React

<Link to>

Change l'URL en JS

Garde le state React

Link : Syntaxe

import { Link } from 'react-router-dom';

<nav>

<Link to="/">Accueil</Link>

<Link to="/about">Ă€ propos</Link>

<Link to="/contact">Contact</Link>

</nav>

to au lieu de href

Même apparence qu'un lien normal, mais comportement différent

Le contenu entre les balises devient le texte du lien

NavLink : Style actif

Link avec une classe spéciale quand la route est active

import { NavLink } from 'react-router-dom';

<NavLink

to="/about"

className={({ isActive }) => isActive ? 'text-blue-500 font-bold' : 'text-gray-500'}

>

Ă€ propos

</NavLink>

Par défaut, NavLink ajoute la classe active

Utile pour les menus de navigation

Routes dynamiques

Capturer des valeurs de l'URL

/product/:id

Les deux-points indiquent un paramètre dynamique

useParams : Extraire l'ID

// Définition de la route

<Route path="/product/:id" element={<Product />} />

// Composant Product.jsx

import { useParams } from 'react-router-dom';

function Product() {

const { id } = useParams();

return <h1>Produit #{id}</h1>;

}

URL: /product/42 affiche "Produit #42"

Exemple : Page produit

function Product() {

const { id } = useParams();

const [product, setProduct] = useState(null);

useEffect(() => {

// Fetch les données avec l'ID

fetch(`/api/products/${id}`)

.then(res => res.json())

.then(setProduct);

}, [id]);

if (!product) return <p>Chargement...</p>;

return (

<div>

<h1>{product.name}</h1>

<p>{product.price} EUR</p>

</div>

);

}

L'ID change = useEffect se relance automatiquement

Routes imbriées

Garder un layout commun

Dashboard avec sidebar commune

Seul le contenu principal change

Outlet : Le point d'insertion

Outlet affiche le composant de la sous-route

// Layout.jsx

import { Outlet } from 'react-router-dom';

function Layout() {

return (

<div className="flex">

<Sidebar />

<main>

<Outlet /> // Les sous-routes s'affichent ici

</main>

</div>

);

}

Outlet = "trou" oĂą les sous-routes s'affichent

Configuration des routes imbriquées

<Route path="/dashboard" element={<Layout />}>

<Route index element={<DashboardHome />} />

<Route path="profile" element={<Profile />} />

<Route path="settings" element={<Settings />} />

</Route>

/dashboard

DashboardHome

/dashboard/profile

Profile

/dashboard/settings

Settings

index = route par défaut quand on visite /dashboard

Routes protégées

Restreindre l'accès aux utilisateurs connectés

Redirection automatique si non connecté

useNavigate : Redirection programmatique

import { useNavigate } from 'react-router-dom';

function Login() {

const navigate = useNavigate();

const handleLogin = () => {

// Après connexion réussie

navigate('/dashboard');

};

return <button onClick={handleLogin}>Se connecter</button>;

}

navigate() remplace history.push() de v5

navigate(-1) pour revenir en arrière

Créer un composant ProtectedRoute

function ProtectedRoute({ children }) {

const { user } = useAuth(); // Votre contexte d'auth

const navigate = useNavigate();

if (!user) {

return <Navigate to="/login" replace />;

}

return children;

}

// Utilisation

<Route

path="/admin"

element={

<ProtectedRoute>

Navigate : Redirection déclarative

import { Navigate } from 'react-router-dom';

<Navigate to="/login" replace />

useNavigate()

Redirection dans un event handler

Après un clic, un submit...

Navigate

Redirection dans le JSX

Rendu conditionnel...

replace évite que l'utilisateur revienne avec le bouton "Retour"

useSearchParams

Gérer les query parameters

/products?category=electronics&sort=price

Les paramètres après le ?

Lire et modifier les search params

import { useSearchParams } from 'react-router-dom';

function Products() {

const [searchParams, setSearchParams] = useSearchParams();

const category = searchParams.get('category');

const sort = searchParams.get('sort');

// Modifier les params

const setCategory = (cat) => {

setSearchParams({ category: cat, sort: sort });

};

}

searchParams.get() retourne null si le param n'existe pas

Exemple : Filtres de produits

function ProductFilters() {

const [searchParams, setSearchParams] = useSearchParams();

const updateFilter = (key, value) => {

const params = new URLSearchParams(searchParams);

if (value) {

params.set(key, value);

} else {

params.delete(key);

}

setSearchParams(params);

};

return (

<select onChange={(e) => updateFilter('category', e.target.value)}>

<option value="">Toutes</option>

<option value="electronics">Électronique</option>

</select>

);

}

L'URL change = partageable et bookmarkable !

Route 404

Gérer les URLs inconnues

path="*"

Capture toutes les routes non définies

Configuration de la route 404

<Routes>

<Route path="/" element={<Home />} />

<Route path="/about" element={<About />} />

<Route path="*" element={<NotFound />} />

</Routes>

Sans cette route, l'utilisateur voit une page vide

// NotFound.jsx

function NotFound() {

return (

<div className="text-center p-10">

<h1>404 - Page non trouvée</h1>

<Link to="/">Retour Ă  l'accueil</Link>

</div>

);

}

Pièges courants à éviter

Utiliser <a href> au lieu de <Link to>

La page se recharge et tout le state React est perdu !

Utilisez toujours Link pour la navigation interne

Oublier le BrowserRouter

Routes, Link, useParams... ne fonctionnent pas sans lui

Enveloppez toute l'application avec BrowserRouter

Path sans / initial dans les sous-routes

path="profile" est relatif, path="/profile" est absolu

Dans les routes imbriquées, utilisez des chemins relatifs

Ne pas gérer la route 404

L'utilisateur voit une page vide sur une URL inconnue

Ajoutez toujours une route path="*"

<a> vs Link : L'erreur classique

L'erreur

<a href="/about">

Ă€ propos

</a>

Recharge la page

Pert le state React

RequĂŞte serveur inutile

La solution

<Link to="/about">

Ă€ propos

</Link>

Change l'URL en JS

Garde le state React

Navigation instantanée

Points clés à retenir

React Router ne recharge PAS la page

Il change le composant affiché selon l'URL

Link remplace <a> pour la navigation interne

Pas de rechargement, pas de perte de state

useParams() pour les paramètres dynamiques

:id dans l'URL devient accessible dans le composant

Outlet pour les routes imbriquées

Permet de garder un layout commun

useSearchParams pour les query parameters

?category=electronics&sort=price

Récapitulatif

BrowserRouter

Enveloppe l'app

Routes / Route

Définit les chemins

Link / NavLink

Navigation sans reload

useParams

/:id dynamique

Outlet

Routes imbriquées

Navigate

Redirection

useSearchParams pour les filtres et query params

path="*" pour la page 404

Exercices pratiques

1. Créer une navigation 3 pages

Home, About, Contact avec Link

2. Page produit dynamique

/product/:id avec useParams

3. Dashboard avec routes imbriquées

Layout + Outlet pour sidebar commune

4. Route protégée

Redirection vers /login si non connecté

5. Filtres avec useSearchParams

?category=electronics&sort=price

Ă€ retenir !

Link to

Jamais <a href> pour la navigation interne

useParams

:id dans path = { id } dans le composant

Outlet

Point d'insertion pour les sous-routes

path="*"

Toujours prévoir la page 404

React Router = SPA avec vraies URLs

Navigation fluide, state préservé, bookmarks possibles

Questions?

React Router est essentiel pour les SPA React

Prochaine étape : pratiquer avec des exercices !