Leçon 2 / 9
22%

Next.js 16 – Leçon 2 : App Router, pages, layouts, routes

L’App Router : la philosophie

L’App Router est le système de routage de Next.js depuis la version 13. Dans Next.js 16, c’est la seule approche recommandée. Le principe : chaque dossier dans app/ correspond à un segment d’URL. La présence ou l’absence de certains fichiers dans ce dossier détermine le comportement de la route.

Structure app/ → routes générées
app/
├── page.tsx            → /
├── blog/
│   ├── page.tsx        → /blog
│   └── [slug]/
│       └── page.tsx    → /blog/mon-article
└── dashboard/
    ├── layout.tsx      → layout partagé
    ├── page.tsx        → /dashboard
    └── settings/
        └── page.tsx    → /dashboard/settings

page.tsx — rendre une route accessible

Un dossier n’est accessible en URL que s’il contient un fichier page.tsx. Sans ce fichier, le dossier peut exister mais la route renvoie 404.

TypeScript app/blog/page.tsx
// Server Component par défaut — s'exécute côté serveur
export default function BlogPage() {
  return (
    <main className="max-w-3xl mx-auto py-12 px-4">
      <h1 className="text-4xl font-bold mb-8">Le Blog</h1>
      <p className="text-gray-600">Accessible sur /blog</p>
    </main>
  );
}

// Métadonnées SEO spécifiques à cette page
export const metadata = {
  title: 'Blog',
  description: 'Tous nos articles',
};

layout.tsx — le layout partagé

Un layout.tsx enveloppe toutes les pages de son dossier et de tous ses sous-dossiers. Il persiste entre les navigations — il ne se re-render pas quand on change de page. Parfait pour la navbar, le sidebar, le footer.

TypeScript app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="flex min-h-screen">
      {/* Sidebar persistante — ne se re-render pas */}
      <aside className="w-64 bg-gray-900 text-white p-6">
        <nav className="space-y-2">
          <a href="/dashboard" className="block p-2 rounded hover:bg-gray-800">Accueil</a>
          <a href="/dashboard/settings" className="block p-2 rounded hover:bg-gray-800">Paramètres</a>
        </nav>
      </aside>

      {/* Contenu de la page courante */}
      <main className="flex-1 p-8">
        {children}
      </main>
    </div>
  );
}
ℹ️
Layouts imbriqués

Les layouts s’emboîtent automatiquement. app/layout.tsx enveloppe tout. app/dashboard/layout.tsx enveloppe uniquement les pages dans dashboard/. Next.js fusionne ces layouts sans que vous ayez à faire quoi que ce soit.

loading.tsx — squelette de chargement

Créez un fichier loading.tsx dans un dossier pour afficher automatiquement un état de chargement pendant que la page se charge. Next.js utilise React Suspense en coulisses.

TypeScript app/blog/loading.tsx
export default function Loading() {
  return (
    <div className="max-w-3xl mx-auto py-12 px-4 space-y-4">
      {/* Skeleton cards */}
      {[...Array(3)].map((_, i) => (
        <div key={i} className="animate-pulse bg-gray-100 rounded-xl h-24" />
      ))}
    </div>
  );
}
💡
Chargement instantané de la navigation

Grâce à loading.tsx, Next.js affiche immédiatement le squelette pendant que les données de la page se chargent. L’utilisateur voit une réponse instantanée au lieu d’un écran blanc.

error.tsx — gestion des erreurs

error.tsx capture les erreurs runtime dans un dossier et ses enfants, sans planter toute l’application. Important : il doit obligatoirement être un Client Component ("use client") car il utilise des hooks React.

TypeScript app/blog/error.tsx
'use client'; // Obligatoire pour error.tsx

export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  return (
    <div className="flex flex-col items-center justify-center min-h-96 gap-4">
      <h2 className="text-2xl font-bold text-red-600">Une erreur est survenue</h2>
      <p className="text-gray-500">{error.message}</p>
      <button
        onClick={reset}
        className="bg-gray-900 text-white px-6 py-2 rounded-xl hover:bg-gray-700"
      >
        Réessayer
      </button>
    </div>
  );
}

not-found.tsx — page 404 personnalisée

TypeScript app/not-found.tsx
import Link from 'next/link';

export default function NotFound() {
  return (
    <div className="flex flex-col items-center justify-center min-h-screen gap-6">
      <span className="text-8xl font-black text-gray-200">404</span>
      <h2 className="text-2xl font-bold">Page introuvable</h2>
      <Link href="/" className="text-blue-600 hover:underline">
        Retour à l'accueil
      </Link>
    </div>
  );
}

Récapitulatif : les fichiers spéciaux

Référence rapide
page.tsx       → Rend la route accessible en URL
layout.tsx     → Enveloppe les pages enfants (persiste)
loading.tsx    → Affiché pendant le chargement (Suspense)
error.tsx      → Capture les erreurs runtime ("use client")
not-found.tsx  → Page 404 personnalisée
template.tsx   → Comme layout mais se re-render à chaque nav
default.tsx    → Fallback pour les parallel routes

Exercice pratique

  • Créez une section app/blog/ avec une page.tsx qui liste 3 articles fictifs
  • Ajoutez un layout.tsx dans app/blog/ avec un titre « Le Blog » en en-tête
  • Ajoutez un loading.tsx avec 3 blocs animate-pulse
  • Ajoutez un not-found.tsx à la racine du projet et vérifiez qu’il s’affiche sur une URL inexistante
  • Observez dans les DevTools React que le layout ne se re-render pas lors de la navigation