---
title: "Routage"
weight: 160
---

# Routage

Documentation [React Router v7](https://reactrouter.com/)

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

> [!TIP]
> **Avec smartcommon, utilisez `<RouteGuard>`** : il couvre 4 modes (`requireAuth`, `requireGuest`, `requireDeviceIdentification`, `requireDeviceIdentified`) et lit directement `useApi().user` / `user.deviceOptions`. Voir [Composants avancés -> RouteGuard](/front/composants-avances#routeguard) pour la version complète. La version manuelle ci-dessous reste utile pédagogiquement ou pour des règles métier qui ne rentrent pas dans ces 4 modes.

### RouteGuard (recommandé)

```
import { RouteGuard } from '@cap-rel/smartcommon';

<Routes>
  <Route element={<RouteGuard requireGuest />}>
    <Route path="/login" element={<LoginPage />} />
    <Route path="/welcome" element={<WelcomePage />} />
  </Route>

  <Route element={<RouteGuard requireDeviceIdentified />}>
    <Route path="/" element={<HomePage />} />
    <Route path="/settings" element={<SettingsPage />} />
  </Route>
</Routes>
```

### Guards d'authentification (manuel)

```
// 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 gst = useGlobalStates();
  const session = gst.get('session');

  if (session) {
    return <Navigate to="/" replace />;
  }

  return <Outlet />;
};

/**
 * Private routes (home, settings, etc.)
 * Redirects to /login if not authenticated
 */
export const PrivateRoutes = () => {
  const gst = useGlobalStates();
  const session = gst.get('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` qui retourne un objet avec des methodes de navigation :

```
import { useNavigation } from '@cap-rel/smartcommon';

const MyComponent = () => {
  const nav = useNavigation();

  return (
    <div>
      {/* Navigation simple */}
      <button onClick={() => nav.navigate('/')}>Accueil</button>
      <button onClick={() => nav.navigate('/settings')}>Paramètres</button>

      {/* Avec paramètres */}
      <button onClick={() => nav.navigate(`/items/${itemId}`)}>Voir l'item</button>

      {/* Retour en arrière */}
      <button onClick={() => nav.navigate(-1)}>Retour</button>

      {/* Remplacer l'historique (builder chainable) */}
      <button onClick={() => nav.replace().to('/login')}>
        Déconnexion
      </button>
    </div>
  );
};
```

### Propriétés retournées

| Propriété | Description |
| --- | --- |
| `nav.navigate(to, options)` | Fonction de navigation React Router |
| `nav.params` | Paramètres de la route (useParams) |
| `nav.searchParams` | Query string (useSearchParams) |
| `nav.location` | Objet location courant |
| `nav.history` | Historique de navigation |
| `nav.replace()` | Builder chainable : remplacer au lieu de pousser |
| `nav.state(value)` | Builder chainable : passer un state |
| `nav.to(path)` | Builder chainable : executer la navigation |

### 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 nav = 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={() => nav.navigate('/')}>Accueil</button>
        <button onClick={() => nav.navigate('/search')}>Recherche</button>
        <button onClick={() => nav.navigate('/profile')}>Profil</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](/front/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 nav = 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={() => nav.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 gst = useGlobalStates();
  const session = gst.get('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 `useNavigation` de SmartCommon
- Utilisez `replace: true` pour 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](/front/animations) - Transitions de pages
- [Composants et pages](/front/composants-et-pages) - Structure des pages
- [Hooks](/front/hooks) - useNavigation
- [Configuration](/front/configuration) - Options du Provider
