Routage dans Next.js¶
Routage basé sur les fichiers¶
Dans Next.js, le routage est basé sur la structure des dossiers dans le répertoire app/. Chaque dossier correspond à un segment de l'URL, et un fichier page.tsx dans ce dossier rend la route accessible.
app/
├── page.tsx → /
├── a-propos/
│ └── page.tsx → /a-propos
└── produits/
├── page.tsx → /produits
└── [id]/
└── page.tsx → /produits/1, /produits/2, etc.
Les fichiers spéciaux¶
Next.js reconnaît plusieurs fichiers spéciaux dans chaque dossier de route :
| Fichier | Rôle |
|---|---|
page.tsx |
Le contenu de la page (rend la route accessible) |
layout.tsx |
Gabarit partagé qui enveloppe les pages enfants |
loading.tsx |
Interface de chargement affichée pendant le chargement |
error.tsx |
Interface d'erreur affichée en cas de problème |
page.tsx¶
Fichier obligatoire pour qu'une route soit accessible. Il exporte le composant qui sera affiché :
export default function Accueil() {
return (
<main>
<h1>Page d'accueil</h1>
<p>Bienvenue sur notre application Next.js!</p>
</main>
);
}
export default function APropos() {
return (
<main>
<h1>À propos</h1>
<p>Cette application est un exemple de routage avec Next.js.</p>
</main>
);
}
layout.tsx¶
Le layout enveloppe les pages enfants. Il est idéal pour les éléments de navigation partagés :
import Link from "next/link";
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="fr">
<body>
<nav>
<Link href="/">Accueil</Link> |{" "}
<Link href="/produits">Produits</Link> |{" "}
<Link href="/a-propos">À propos</Link>
</nav>
<hr />
{children}
</body>
</html>
);
}
Le composant {children} sera remplacé par le contenu de la page active. Ceci est similaire au concept de <Outlet /> dans React Router.
loading.tsx¶
Affiche un indicateur de chargement pendant que la page se charge :
export default function Loading() {
return <p>Chargement des produits...</p>;
}
error.tsx¶
Gère les erreurs dans un segment de route. Ce fichier doit obligatoirement être un Client Component ("use client") :
"use client";
export default function Error({
error,
reset,
}: {
error: Error;
reset: () => void;
}) {
return (
<div>
<h2>Une erreur est survenue!</h2>
<p>{error.message}</p>
<button onClick={() => reset()}>Réessayer</button>
</div>
);
}
Routes dynamiques avec [parametre]¶
Pour créer une route dynamique, on utilise un nom de dossier entre crochets. Par exemple, app/produits/[id]/page.tsx accepte n'importe quelle valeur pour id.
interface ProduitPageProps {
params: Promise<{ id: string }>;
}
export default async function ProduitDetail({ params }: ProduitPageProps) {
const { id } = await params;
return (
<main>
<h1>Détail du produit #{id}</h1>
<p>Vous consultez le produit avec l'identifiant : {id}</p>
</main>
);
}
Le paramètre est accessible via la propriété params du composant. Dans Next.js 15+, params est une Promise qu'il faut attendre avec await.
Navigation avec le composant Link¶
Pour naviguer entre les pages, utilisez le composant <Link> de Next.js plutôt que des balises <a> classiques. Le composant <Link> effectue une navigation côté client sans recharger la page complète.
import Link from "next/link";
const produits = [
{ id: 1, nom: "Clavier mécanique" },
{ id: 2, nom: "Souris ergonomique" },
{ id: 3, nom: "Écran 27 pouces" },
];
export default function Produits() {
return (
<main>
<h1>Liste des produits</h1>
<ul>
{produits.map((produit) => (
<li key={produit.id}>
<Link href={`/produits/${produit.id}`}>{produit.nom}</Link>
</li>
))}
</ul>
</main>
);
}
Routes imbriquées et layouts partagés¶
Les layouts sont partagés entre les routes enfants. Lorsque vous naviguez entre des pages qui partagent un layout, seul le contenu de la page change, pas le layout.
app/
├── layout.tsx ← Layout racine (navigation principale)
├── page.tsx ← Page d'accueil
└── produits/
├── layout.tsx ← Layout pour la section produits
├── page.tsx ← Liste des produits
└── [id]/
└── page.tsx ← Détail d'un produit
Avec cette structure, le layout racine (app/layout.tsx) enveloppe tout, et le layout des produits (app/produits/layout.tsx) enveloppe seulement les pages de la section produits.
Comparaison avec React Router¶
| Concept | React Router | Next.js |
|---|---|---|
| Définition des routes | <Route path="/produits" element={<Produits />} /> |
Dossier app/produits/page.tsx |
| Routes dynamiques | <Route path="/produits/:id" ... /> |
Dossier app/produits/[id]/page.tsx |
| Accès aux paramètres | useParams() |
Propriété params du composant |
| Navigation | <Link to="/produits"> |
<Link href="/produits"> |
| Layout partagé | <Outlet /> dans un composant parent |
layout.tsx avec {children} |
| Chargement | Géré manuellement | loading.tsx automatique |
| Erreurs | Géré manuellement | error.tsx automatique |