Routage
Documentation React Router v7
SmartMaker utilise React Router pour gérer la navigation entre les pages de l'application (Single Page Application).
Configuration de base
Créer le Router
// src/components/app/Router/index.jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { LoginPage } from '../../pages/public/LoginPage';
import { HomePage } from '../../pages/private/HomePage';
import { Error404Page } from '../../pages/errors/Error404Page';
export const Router = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/" element={<HomePage />} />
<Route path="*" element={<Error404Page />} />
</Routes>
</BrowserRouter>
);
};
Intégrer dans App.jsx
// src/App.jsx
import { Provider } from '@cap-rel/smartcommon';
import { Router } from './components/app/Router';
import { config } from './appConfig';
export const App = () => {
return (
<Provider config={config}>
<Router />
</Provider>
);
};
Routes protégées
Guards d'authentification
// src/components/app/Router/Guards/index.jsx
import { Outlet, Navigate } from 'react-router-dom';
import { useGlobalStates } from '@cap-rel/smartcommon';
/**
* Routes publiques (login, register, etc.)
* Redirige vers / si déjà connecté
*/
export const PublicRoutes = () => {
const [session] = useGlobalStates('session');
if (session) {
return <Navigate to="/" replace />;
}
return <Outlet />;
};
/**
* Routes privées (home, settings, etc.)
* Redirige vers /login si non connecté
*/
export const PrivateRoutes = () => {
const [session] = useGlobalStates('session');
if (!session) {
return <Navigate to="/login" replace />;
}
return <Outlet />;
};
Utiliser les Guards
// src/components/app/Router/index.jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { PublicRoutes, PrivateRoutes } from './Guards';
// Pages publiques
import { WelcomePage } from '../../pages/public/WelcomePage';
import { LoginPage } from '../../pages/public/LoginPage';
// Pages privées
import { HomePage } from '../../pages/private/HomePage';
import { SettingsPage } from '../../pages/private/SettingsPage';
import { ItemPage } from '../../pages/private/ItemPage';
// Erreurs
import { Error404Page } from '../../pages/errors/Error404Page';
export const Router = () => {
return (
<BrowserRouter>
<Routes>
{/* Routes publiques */}
<Route element={<PublicRoutes />}>
<Route path="/welcome" element={<WelcomePage />} />
<Route path="/login" element={<LoginPage />} />
</Route>
{/* Routes privées */}
<Route element={<PrivateRoutes />}>
<Route path="/" element={<HomePage />} />
<Route path="/settings" element={<SettingsPage />} />
<Route path="/items/:id" element={<ItemPage />} />
</Route>
{/* Fallback 404 */}
<Route path="*" element={<Error404Page />} />
</Routes>
</BrowserRouter>
);
};
Navigation
Hook useNavigation
SmartCommon expose useNavigation pour naviguer entre les pages :
import { useNavigation } from '@cap-rel/smartcommon';
const MyComponent = () => {
const navigate = useNavigation();
return (
<div>
{/* Navigation simple */}
<button onClick={() => navigate('/')}>Accueil</button>
<button onClick={() => navigate('/settings')}>Paramètres</button>
{/* Avec paramètres */}
<button onClick={() => navigate(`/items/${itemId}`)}>Voir l'item</button>
{/* Retour en arrière */}
<button onClick={() => navigate(-1)}>Retour</button>
{/* Remplacer l'historique (pas de retour possible) */}
<button onClick={() => navigate('/login', { replace: true })}>
Déconnexion
</button>
</div>
);
};
Composant Link
Pour les liens simples, utilisez le composant Link :
import { Link } from 'react-router-dom';
const Navigation = () => {
return (
<nav>
<Link to="/">Accueil</Link>
<Link to="/settings">Paramètres</Link>
<Link to="/items/123">Item 123</Link>
</nav>
);
};
Paramètres de route
Paramètres dynamiques
// Route avec paramètre :id
<Route path="/items/:id" element={<ItemPage />} />
// Récupérer le paramètre
import { useParams } from 'react-router-dom';
const ItemPage = () => {
const { id } = useParams(); // id = "123" pour /items/123
return <div>Item #{id}</div>;
};
Paramètres multiples
// Route avec plusieurs paramètres
<Route path="/users/:userId/posts/:postId" element={<PostPage />} />
const PostPage = () => {
const { userId, postId } = useParams();
// ...
};
Query strings
import { useSearchParams } from 'react-router-dom';
const SearchPage = () => {
const [searchParams, setSearchParams] = useSearchParams();
// Lire : /search?q=test&page=2
const query = searchParams.get('q'); // "test"
const page = searchParams.get('page'); // "2"
// Modifier
const handleSearch = (newQuery) => {
setSearchParams({ q: newQuery, page: '1' });
};
return (
<input
value={query || ''}
onChange={(e) => handleSearch(e.target.value)}
/>
);
};
Routes imbriquées
Layout partagé
// src/components/app/Router/index.jsx
<Routes>
<Route element={<PrivateRoutes />}>
{/* Layout avec navigation bottom */}
<Route element={<MainLayout />}>
<Route path="/" element={<HomePage />} />
<Route path="/search" element={<SearchPage />} />
<Route path="/profile" element={<ProfilePage />} />
</Route>
{/* Pages sans navigation bottom */}
<Route path="/items/:id" element={<ItemPage />} />
<Route path="/settings" element={<SettingsPage />} />
</Route>
</Routes>
Composant Layout
// src/components/layouts/MainLayout/index.jsx
import { Outlet } from 'react-router-dom';
import { useNavigation } from '@cap-rel/smartcommon';
export const MainLayout = () => {
const navigate = useNavigation();
return (
<div className="min-h-screen flex flex-col">
{/* Contenu de la page (Outlet = enfant de la route) */}
<main className="flex-1">
<Outlet />
</main>
{/* Navigation fixe en bas */}
<nav className="bg-white shadow-lg p-2 flex justify-around">
<button onClick={() => navigate('/')}>🏠</button>
<button onClick={() => navigate('/search')}>🔍</button>
<button onClick={() => navigate('/profile')}>👤</button>
</nav>
</div>
);
};
Animations de transition
Configuration dans appConfig
// appConfig.js
export const config = {
pages: {
// Depuis la home
"/": {
"/settings": "slideLeft", // Home → Settings : slide vers la gauche
"/items/*": "slideLeft", // Home → Item : slide vers la gauche
"*": "fade", // Autres : fade
},
// Depuis settings
"/settings": {
"/": "slideRight", // Settings → Home : slide vers la droite
},
// Par défaut
"*": "fade",
},
};
Animations disponibles
| Animation | Description |
|---|---|
fade | Fondu enchaîné |
slideLeft | Glissement vers la gauche |
slideRight | Glissement vers la droite |
zoom | Zoom avant/arrière |
Voir Animations pour plus de détails.
Gestion d'erreurs
Page 404
// src/components/pages/errors/Error404Page/index.jsx
import { useNavigation } from '@cap-rel/smartcommon';
export const Error404Page = () => {
const navigate = useNavigation();
return (
<div className="min-h-screen flex flex-col items-center justify-center p-4">
<h1 className="text-6xl font-bold text-gray-300 mb-4">404</h1>
<p className="text-gray-600 mb-8">Page non trouvée</p>
<button
onClick={() => navigate('/')}
className="bg-primary text-white px-6 py-3 rounded-lg"
>
Retour à l'accueil
</button>
</div>
);
};
Redirection conditionnelle
import { Navigate, useLocation } from 'react-router-dom';
import { useGlobalStates } from '@cap-rel/smartcommon';
const RequireAuth = ({ children }) => {
const [session] = useGlobalStates('session');
const location = useLocation();
if (!session) {
// Sauvegarder l'URL pour rediriger après login
return <Navigate to="/login" state={{ from: location }} replace />;
}
return children;
};
Bonnes pratiques
Structure des routes
- Groupez les routes par type (public, private, errors)
- Utilisez des guards pour la protection
- Placez le fallback
*en dernier
Navigation
- Préférez
useNavigationde SmartCommon - Utilisez
replace: truepour les redirections (login, logout) - Évitez les chemins hardcodés, utilisez des constantes
Performance
- Lazy loading pour les grosses pages
- Animations légères sur mobile
- Pré-chargement des données critiques
Voir aussi
- Animations - Transitions de pages
- Composants et pages - Structure des pages
- Hooks - useNavigation
- Configuration - Options du Provider