🔄 Navigation Programmatique avec React Router
La navigation programmatique déclenche un changement de route par le code (hook ou API) plutôt que par un lien <Link>. Utile pour : redirection post‑authentification, retour après annulation, étape suivante d’un wizard, gestion d’erreurs.
🧠 Fondamentaux
useNavigate() retourne une fonction navigate(to, options?) qui pousse une entrée dans l’historique (par défaut). Options clés : { replace: true, state: any }.
📦 Exemple minimal
import { useNavigate } from 'react-router';
function FormComponent() {
const navigate = useNavigate();
function handleSubmit(e) {
e.preventDefault();
// ... traitement
navigate('/success');
}
return <form onSubmit={handleSubmit}>{/* champs */}</form>;
}♻️ Remplacer l’entrée d’historique
Lorsque l’on ne veut pas que l’utilisateur revienne sur la page précédente (ex: après login).
navigate('/dashboard', { replace: true });📦 Passer un état de navigation
Transmettre des données éphémères sans polluer l’URL.
navigate('/checkout', { state: { fromCart: true, total: 42.9 } });Dans la cible :
import { useLocation } from 'react-router';
const { state } = useLocation();🔁 Navigation relative & historique
navigate(-1); // revenir en arrière
navigate(1); // aller en avant (si entrée disponible)🚦 Guards & conditions
Rediriger si condition non respectée (auth, rôle, données).
function Protected({ isAuth }) {
const navigate = useNavigate();
if (!isAuth) {
navigate('/login', { replace: true });
return null;
}
return <p>Zone protégée</p>;
}🪜 Combiner avec paramètres
function GoUser({ id }) {
const navigate = useNavigate();
return <button onClick={() => navigate(`/users/${id}`)}>Voir user {id}</button>;
}🧪 Gestion d’erreur + redirection
try {
await submitData(form);
navigate('/done');
} catch (e) {
navigate('/error', { state: { message: e.message } });
}🛡️ Accessibilité
Après navigation programmée vers une vue structurée, placer le focus sur un titre ou un conteneur.
useEffect(() => { document.getElementById('page-title')?.focus(); }, []);Utiliser tabIndex="-1" sur le titre ciblé pour autoriser le focus.
💤 Lazy + navigate
Fonctionne si la route cible est lazy : la transition charge le chunk nécessaire.
🛠️ Exercices
- Après login simulé, rediriger vers
/profilavecreplace. - Ajouter un bouton « Revenir » qui désactive si historique vide (tester
window.history.length). - Passer un état
{ flash: 'Profil mis à jour' }puis l’afficher et l’effacer. - Implémenter une redirection automatique vers
/loginsi token absent.
import { BrowserRouter, Routes, Route, useNavigate, useLocation } from 'react-router';
function Login() {
const navigate = useNavigate();
function handleLogin() {
// fake token
localStorage.setItem('token', 'abc');
navigate('/profil', { replace: true, state: { flash: 'Bienvenue !' } });
}
return <button onClick={handleLogin}>Se connecter</button>;
}
function Profil() {
const { state } = useLocation();
return <div>{state?.flash && <p>{state.flash}</p>}<h2>Profil</h2></div>;
}
function Guard({ children }) {
const navigate = useNavigate();
const token = localStorage.getItem('token');
useEffect(() => { if (!token) navigate('/login', { replace: true }); }, [token, navigate]);
return token ? children : null;
}
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/profil" element={<Guard><Profil /></Guard>} />
</Routes>
</BrowserRouter>
);
}📚 Ressources
- API navigate : https://reactrouter.com/en/main/hooks/use-navigate
- Location & state : https://reactrouter.com/en/main/hooks/use-location
- Accessibilité focus SPA : https://www.w3.org/WAI/ARIA/apg/practices/landmarks/
⚡ TLDR
useNavigate()pour déclencher navigationnavigate(to, { replace, state })pour optionsnavigate(-1)/navigate(1)pour historique- Guards : vérifier auth puis rediriger (souvent
replace: true) - Focus manuel après navigation pour accessibilité
- Éviter redirections dans rendu profond sans condition claire
Voir aussi : /react/routage/dynamiques pour paramètres et /react/donnees pour chargement conditionnel.