React Router
Navigue entre les pages sans recharger le navigateur.
8.1Installation
npm install react-router-dom8.2Setup de base
React Router s'installe autour de ton app avec BrowserRouter, puis tu définis tes routes avec Routes et Route :
// src/main.tsx
import { BrowserRouter } from 'react-router-dom'
ReactDOM.createRoot(document.getElementById('root')!).render(
<BrowserRouter>
<App />
</BrowserRouter>
)
// src/App.tsx
import { Routes, Route } from 'react-router-dom'
import { Home } from './pages/Home'
import { About } from './pages/About'
import { Contact } from './pages/Contact'
import { NotFound } from './pages/NotFound'
function App() {
return (
<div>
<Header />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="*" element={<NotFound />} /> {/* 404 */}
</Routes>
<Footer />
</div>
)
}8.3Navigation avec Link et NavLink
N'utilise jamais <a href> pour naviguer dans une app React ! Ça rechargerait la page. Utilise Link ou NavLink :
import { Link, NavLink } from 'react-router-dom'
function Header() {
return (
<nav>
{/* Link : navigation simple */}
<Link to="/">Accueil</Link>
{/* NavLink : ajoute une classe "active" automatiquement */}
<NavLink
to="/about"
className={({ isActive }) => isActive ? "font-bold text-blue-600" : "text-slate-600"}
>
À propos
</NavLink>
<NavLink to="/contact" className={({ isActive }) => isActive ? "font-bold text-blue-600" : "text-slate-600"}>
Contact
</NavLink>
</nav>
)
}8.4Routes dynamiques
Comme les routes dynamiques en Next.js ([slug]), React Router utilise le :parametre :
// Définition de la route
<Route path="/produit/:id" element={<PageProduit />} />
// Composant : récupère le paramètre
import { useParams } from 'react-router-dom'
function PageProduit() {
const { id } = useParams<{ id: string }>()
return <h1>Produit n°{id}</h1>
}
// Navigation vers cette route
<Link to="/produit/42">Voir le produit 42</Link>8.5Routes imbriquées (Nested Routes)
Comme les layouts dans Next.js, tu peux imbriquer des routes pour partager un layout :
import { Outlet } from 'react-router-dom'
// Layout partagé pour le dashboard
function DashboardLayout() {
return (
<div className="flex">
<aside>
<NavLink to="/dashboard">Vue d'ensemble</NavLink>
<NavLink to="/dashboard/stats">Statistiques</NavLink>
<NavLink to="/dashboard/settings">Paramètres</NavLink>
</aside>
<main>
<Outlet /> {/* ← Les sous-routes s'affichent ici */}
</main>
</div>
)
}
// Configuration
<Routes>
<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<DashboardHome />} />
<Route path="stats" element={<DashboardStats />} />
<Route path="settings" element={<DashboardSettings />} />
</Route>
</Routes>8.6Navigation programmatique
Pour naviguer après une action (soumission de formulaire, login...) :
import { useNavigate } from 'react-router-dom'
function LoginForm() {
const navigate = useNavigate()
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
const success = await login(email, password)
if (success) {
navigate('/dashboard') // Redirection
// navigate('/dashboard', { replace: true }) // Sans retour arrière
}
}
return <form onSubmit={handleSubmit}>...</form>
}
// Accéder aux query params
import { useSearchParams } from 'react-router-dom'
function SearchPage() {
const [searchParams, setSearchParams] = useSearchParams()
const query = searchParams.get('q') || ''
return (
<input
value={query}
onChange={e => setSearchParams({ q: e.target.value })}
/>
// URL: /search?q=react
)
}8.7Route protégée
Pour protéger certaines pages (ex: tableau de bord réservé aux utilisateurs connectés) :
import { Navigate } from 'react-router-dom'
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { user } = useAuth() // Ton hook d'auth
if (!user) {
return <Navigate to="/login" replace />
}
return children
}
// Utilisation
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/dashboard" element={
<ProtectedRoute>
<DashboardPage />
</ProtectedRoute>
} />
</Routes>