🧱 Routes Dynamiques & Paramètres
Les routes dynamiques permettent d’afficher un contenu en fonction de segments variables de l’URL (ex: /produits/A1, /users/42). On utilise la syntaxe :param dans le chemin et le hook useParams() pour récupérer les valeurs.
🧠 Fondamentaux
Une route dynamique = chemin avec segment paramétré :id + composant qui lit la valeur. Avantages :
- URL sémantiques et partageables
- Navigation côté client rapide (SPA)
- Chargement ciblé de données (fetch selon ID)
📦 Exemple minimal
import { BrowserRouter, Routes, Route, useParams } from 'react-router';
function Product() {
const { id } = useParams();
return <p>Produit #{id}</p>;
}
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/product/:id" element={<Product />} />
</Routes>
</BrowserRouter>
);
}🔍 Paramètres multiples
<Route path="/shop/:category/:sku" element={<Item />} />
function Item() {
const { category, sku } = useParams();
return <p>{category} – référence {sku}</p>;
}🕸️ Recherche (Query string)
Les paramètres d’URL ne couvrent pas tout. Pour une pagination ou un tri : utiliser l’API URLSearchParams sur window.location.search ou useSearchParams().
import { useSearchParams } from 'react-router';
function ProductsList() {
const [searchParams, setSearchParams] = useSearchParams();
const page = searchParams.get('page') ?? '1';
return (
<div>
<p>Page {page}</p>
<button onClick={() => setSearchParams({ page: Number(page) + 1 })}>Suivant</button>
</div>
);
}🪜 Routes imbriquées + paramètres
On peut imbriquer une route paramétrée et des sous‑vues (ex: /users/:id/settings).
import { BrowserRouter, Routes, Route, Outlet, useParams } from 'react-router';
function UserLayout() {
const { id } = useParams();
return (
<div>
<h2>Utilisateur {id}</h2>
<Outlet />
</div>
);
}
function Profile() { return <p>Profil</p>; }
function Preferences() { return <p>Préférences</p>; }
export function AppNestedParams() {
return (
<BrowserRouter>
<Routes>
<Route path="/users/:id" element={<UserLayout />}>
<Route path="profile" element={<Profile />} />
<Route path="preferences" element={<Preferences />} />
</Route>
</Routes>
</BrowserRouter>
);
}🃏 Wildcard / Catch-all
Pour gérer routes non définies ou segments supplémentaires.
<Route path="/docs/*" element={<Docs />} />Dans Docs, vous pouvez analyser location.pathname pour router manuellement ou charger un article par slug.
🚫 404 (Not Found)
Toujours prévoir une route de repli.
<Route path="*" element={<p>Page introuvable</p>} />🛡️ Validation d’ID
Ne faites pas confiance directement à id. Vérifiez format (regex) avant de lancer un fetch.
function Product() {
const { id } = useParams();
if (!/^\w{2,10}$/.test(id)) return <p>ID invalide</p>;
return <p>Produit #{id}</p>;
}💤 Lazy + paramètre
Combiner lazy loading pour vues spécialisées.
import { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router';
const Product = lazy(() => import('./Product'));
export function AppLazyDynamic() {
return (
<BrowserRouter>
<Suspense fallback={<p>Chargement…</p>}>
<Routes>
<Route path="/product/:id" element={<Product />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}🛠️ Exercices
- Crée
/articles/:sluget affiche le slug formaté (remplacer-par espaces capitalisés). - Ajoute pagination via
?page=avecuseSearchParams(). - Ajoute une route catch‑all
/articles/*qui affiche « Archive » pour tout chemin non spécifique. - Valide le slug avec regex (
^[a-z0-9-]+$).
// Fichier: src/App.jsx
import { BrowserRouter, Routes, Route, useParams, useSearchParams } from 'react-router';
function Article() {
const { slug } = useParams();
if (!/^[a-z0-9-]+$/.test(slug)) return <p>Slug invalide</p>;
const title = slug.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(' ');
return <h2>{title}</h2>;
}
function ArticlesIndex() {
const [sp, setSp] = useSearchParams();
const page = sp.get('page') ?? '1';
return (
<div>
<p>Page {page}</p>
<button onClick={() => setSp({ page: String(Number(page) + 1) })}>Suivant</button>
</div>
);
}
function Archive() { return <p>Archive des articles</p>; }
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/articles" element={<ArticlesIndex />} />
<Route path="/articles/:slug" element={<Article />} />
<Route path="/articles/*" element={<Archive />} />
<Route path="*" element={<p>404</p>} />
</Routes>
</BrowserRouter>
);
}📚 Ressources
- Docs officielle paramètres : https://reactrouter.com/en/main/hooks/use-params
- Recherche / query : https://reactrouter.com/en/main/hooks/use-search-params
- Wildcards & patterns : https://reactrouter.com/en/main/route/route
⚡ TLDR
- Paramètres :
:id+useParams() - Query string :
useSearchParams()pour lire/écrire - Imbrication avec paramètre : parent +
<Outlet /> - Catch-all :
*pour 404 ou wildcard - Valider / sécuriser les identifiants avant fetch
- Lazy sur vues lourdes paramétrées
Voir aussi : /react/routage pour la vue d’ensemble et /react/donnees pour le chargement côté client.