Le Routing en React - Cours n°3
Les Paramètres d'URL - Rendons nos Routes Dynamiques ! 🎢
Les Paramètres d'URL : Le Concept
Imaginez que vous créez un e-commerce. Vous ne pouvez pas créer une route pour chaque produit manuellement ! C'est là qu'interviennent les paramètres d'URL. Au lieu d'avoir :
<Route path="/product/chaussure" />
<Route path="/product/pantalon" />
<Route path="/product/chapeau" />
Vous aurez une seule route dynamique :
<Route path="/product/:id" />
Mise en Pratique avec un Example Concret : Notre Bibliothèque de Films
// src/data/movies.js
export const movies = [
{ id: 1, title: "Inception", director: "Christopher Nolan", year: 2010 },
{ id: 2, title: "The Matrix", director: "Lana et Lilly Wachowski", year: 1999 },
// ... plus de films
]
// src/pages/MoviesList.jsx
import { Link } from 'react-router-dom'
import { movies } from '../data/movies'
export default function MoviesList() {
return (
<div className="movies-grid">
<h1>Notre Collection de Films</h1>
{movies.map(movie => (
<Link
key={movie.id}
to={`/movie/${movie.id}`}
className="movie-card"
>
<h2>{movie.title}</h2>
<p>Réalisé par {movie.director}</p>
<p>Année : {movie.year}</p>
</Link>
))}
</div>
)
}
// src/pages/MovieDetail.jsx
import { useParams, useNavigate } from 'react-router-dom'
import { movies } from '../data/movies'
export default function MovieDetail() {
// useParams récupère les paramètres de l'URL
const { id } = useParams()
const navigate = useNavigate()
// Trouvons notre film
const movie = movies.find(m => m.id === parseInt(id))
// Si le film n'existe pas, redirigeons vers une page d'erreur
if (!movie) {
return navigate('/not-found', { replace: true })
}
return (
<div className="movie-detail">
<h1>{movie.title}</h1>
<div className="movie-info">
<p>Réalisé par {movie.director}</p>
<p>Sorti en {movie.year}</p>
</div>
<button onClick={() => navigate(-1)}>
Retour à la liste
</button>
</div>
)
}
Paramètres de Recherche (Query Parameters)
Les paramètres de recherche sont parfaits pour le filtrage et le tri :
// src/pages/MoviesList.jsx (version améliorée)
import { useSearchParams } from 'react-router-dom'
export default function MoviesList() {
const [searchParams, setSearchParams] = useSearchParams()
const year = searchParams.get('year')
const sortBy = searchParams.get('sortBy')
// Filtrons et trions nos films
let filteredMovies = [...movies]
if (year) {
filteredMovies = filteredMovies.filter(
movie => movie.year === parseInt(year)
)
}
if (sortBy === 'year') {
filteredMovies.sort((a, b) => a.year - b.year)
} else if (sortBy === 'title') {
filteredMovies.sort((a, b) => a.title.localeCompare(b.title))
}
return (
<div>
<div className="filters">
<select
value={year || ''}
onChange={e => {
const newYear = e.target.value
if (newYear) {
setSearchParams(prev => {
prev.set('year', newYear)
return prev
})
} else {
setSearchParams(prev => {
prev.delete('year')
return prev
})
}
}}
>
<option value="">Toutes les années</option>
{[...new Set(movies.map(m => m.year))].map(year => (
<option key={year} value={year}>{year}</option>
))}
</select>
<select
value={sortBy || ''}
onChange={e => {
setSearchParams(prev => {
if (e.target.value) {
prev.set('sortBy', e.target.value)
} else {
prev.delete('sortBy')
}
return prev
})
}}
>
<option value="">Tri par défaut</option>
<option value="year">Année</option>
<option value="title">Titre</option>
</select>
</div>
{/* Liste des films comme avant */}
</div>
)
}
Jour 3-4 : Routes Protégées et Authentification 🔒
Création d'un Système d'Auth Simple
// src/contexts/AuthContext.jsx
import { createContext, useContext, useState } from 'react'
const AuthContext = createContext(null)
export function AuthProvider({ children }) {
const [user, setUser] = useState(null)
const login = (username) => {
setUser({ username })
}
const logout = () => {
setUser(null)
}
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
)
}
export const useAuth = () => useContext(AuthContext)
// src/components/ProtectedRoute.jsx
import { Navigate, useLocation } from 'react-router-dom'
import { useAuth } from '../contexts/AuthContext'
export default function ProtectedRoute({ children }) {
const { user } = useAuth()
const location = useLocation()
if (!user) {
// On sauvegarde l'URL où l'utilisateur voulait aller
return <Navigate to="/login" state={{ from: location }} replace />
}
return children
}
// Utilisation dans App.jsx
function App() {
return (
<AuthProvider>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/movie/:id" element={<MovieDetail />} />
{/* Route protégée */}
<Route
path="/profile"
element={
<ProtectedRoute>
<Profile />
</ProtectedRoute>
}
/>
</Routes>
</AuthProvider>
)
}
// src/pages/Login.jsx
import { useAuth } from '../contexts/AuthContext'
import { useNavigate, useLocation } from 'react-router-dom'
export default function Login() {
const { login } = useAuth()
const navigate = useNavigate()
const location = useLocation()
const from = location.state?.from?.pathname || '/'
const handleSubmit = (e) => {
e.preventDefault()
const username = e.target.username.value
login(username)
navigate(from, { replace: true })
}
return (
<form onSubmit={handleSubmit}>
<h1>Connexion</h1>
<input
name="username"
type="text"
placeholder="Nom d'utilisateur"
/>
<button type="submit">Se connecter</button>
</form>
)
}
Exercice Pratique : Création d'une Mini-Application de Blog
Créez un blog avec :
- Une liste d'articles avec filtres (par catégorie, date)
- Une page détaillée pour chaque article
- Une section admin protégée pour créer/éditer des articles
- Un système de commentaires (bonus)
Points à implémenter :
- Routes dynamiques pour les articles (
/post/:id) - Paramètres de recherche pour les filtres
- Routes protégées pour l'administration
- Navigation programmatique après création/édition
Conseils et Astuces 🎯
- Gestion des Paramètres :
- Utilisez toujours
parseInt()pour les IDs numériques - Validez toujours les paramètres reçus
- Prévoyez des valeurs par défaut
- Sécurité :
- Les routes protégées ne sont qu'une première couche de sécurité
- N'oubliez pas la validation côté serveur
- Gérez proprement les tokens d'authentification
- UX :
- Ajoutez des loaders pendant le chargement
- Gérez les cas d'erreur
- Permettez toujours de revenir en arrière
Pour la Semaine Prochaine...
Nous explorerons la gestion avancée des erreurs et les layouts complexes. Préparez-vous à devenir de vrais architectes du routing ! 🏗️