Aller au contenu

Routage dans Next.js

Routage basé sur l'arborescence sous app/

Au lieu d'un module externe comme React Router, Next.JS se fit sur la structure des répertoires sous app/. Chaque dossier est une partie de l'URL. (par exemple, /app/login serait l'url http://localhost:3000/login). Next.JS lit le fichier page.tsx pour rendre le chemin accessible.

app/
├── page.tsx             
├── a-propos/
│   └── page.tsx         
└── produits/
    ├── page.tsx          
    └── [id]/
        └── page.tsx       

page.tsx

Fichier essentiel pour le bon fonctionnement d'une route. C'est en fait un composant React qui doit être exporté. Le nom du composant n'a pas beaucoup d'importance.

app/page.tsx
export default function Accueil() {
  return (
    <main>
      <h1>Page d&apos;accueil</h1>
      <p>Bienvenue sur notre application Next.js!</p>
    </main>
  );
}
app/a-propos/page.tsx
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 look des pages enfants, idéal à la racine de pages ayant un look similaire :

app/layout.tsx
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, un peu comme <Outlet /> dans React Router.

loading.tsx

Pour avoir un indicateur de chargement d'une page qui prend plus de temps à charger :

app/produits/loading.tsx
export default function Loading() {
  return <p>Chargement des produits...</p>;
}

error.tsx

Si vous voulez gérer localement les erreurs. Ce fichier doit obligatoirement être un Client Component ("use client") :

app/produits/error.tsx
"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]

Il arrive qu'on désire créer des pages dynamiques, accessible par un identifiant. Imaginez une page de produit qui est accessible par /produit/1234 (1234 étant le code de produit). Pour faire ça, on crée une route telle que ceci : app/produit/[id]/page.tsx qui accepte n'importe quelle valeur pour id.

app/produits/[id]/page.tsx
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&apos;identifiant : {id}</p>
    </main>
  );
}

Le paramètre est accessible via la propriété params du composant qui est une Promise qu'il faut attendre avec await.

Pour faire des liens internes dans votre application, utilise le composant <Link> de Next.js plutôt que des <a>. Le composant <Link> effectue une navigation côté client sans recharger la page complète.

app/produits/page.tsx
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>
  );
}