Maîtriser Next.js : Construire des Applications Web Full-Stack Performantes et Scalables
Maîtriser Next.js : Construire des Applications Web Full-Stack Performantes et Scalables

Le Routage et la Création de Pages dans Next.js

Bienvenue dans cette leçon consacrée à un pilier fondamental de Next.js : le routage et la création de pages. Comprendre comment Next.js gère les chemins d'accès (URLs) de votre application est essentiel pour bâtir des expériences utilisateur fluides, performantes et optimisées pour le référencement. Dans le cadre de notre cours "Maîtriser Next.js : Construire des Applications Web Full-Stack Performantes et Scalables", le routage est la première étape pour donner vie à votre application.

Introduction au Routage dans Next.js

Le routage est le mécanisme qui permet à votre application de passer d'une "page" ou d'une "vue" à l'autre en fonction de l'URL demandée par l'utilisateur. Contrairement aux applications React traditionnelles qui utilisent souvent des bibliothèques de routage côté client (comme React Router), Next.js adopte une approche unique et puissante : le routage basé sur le système de fichiers.

Cette approche simplifie grandement le développement en associant directement la structure de vos fichiers à la structure de vos URLs. Chaque fichier JavaScript, TypeScript ou JSX/TSX placé dans le répertoire pages devient automatiquement une route de votre application. Ce modèle apporte des avantages majeurs :

  • Simplicité et Intuition : Plus besoin de configurer manuellement les routes, Next.js s'en charge pour vous.
  • Performance : Next.js peut pré-rendre les pages (SSR, SSG) et pré-charger les ressources associées, offrant une expérience utilisateur ultra-rapide.
  • SEO Amélioré : Grâce au rendu côté serveur, les moteurs de recherche peuvent facilement explorer et indexer le contenu de vos pages.

Plongeons dans les détails de ce système ingénieux.

I. Le Routage Basé sur le Système de Fichiers (File-System Based Routing)

Le cœur du routage dans Next.js réside dans le dossier pages à la racine de votre projet. Toute page React exportée par défaut depuis un fichier dans ce dossier devient une route accessible via le navigateur.

1. Création de Pages Statiques

  • Page d'accueil (/) : Le fichier index.js (ou .jsx, .ts, .tsx) directement dans le dossier pages correspond à la route racine de votre application (/).

  • Pages simples : Un fichier nommé about.js dans le dossier pages sera accessible via l'URL /about.

  • Routes imbriquées : Pour créer des routes imbriquées (par exemple, /blog/mon-article), il suffit de créer des dossiers dans pages. Un fichier pages/blog/first-post.js correspondra à l'URL /blog/first-post.

Exemple de Structure de Fichiers et de Routes :

votre-projet/
├── pages/
│   ├── index.js          // -> /
│   ├── about.js          // -> /about
│   └── blog/
│       └── index.js      // -> /blog
│       └── first-post.js // -> /blog/first-post

Exemple de Code :

// pages/index.js
import Head from 'next/head';

export default function HomePage() {
  return (
    <div>
      <Head>
        <title>Accueil - Mon Super Site</title>
      </Head>
      <h1>Bienvenue sur la page d'accueil !</h1>
      <p>Ceci est notre page principale.</p>
    </div>
  );
}

Explication : Ce fichier index.js définit la page qui sera rendue lorsque l'utilisateur accède à la racine de votre application (par exemple, http://localhost:3000/). Le composant Head de Next.js permet de gérer les balises <head> de votre document HTML, ce qui est crucial pour le SEO et l'apparence de votre page dans les résultats de recherche ou les onglets du navigateur.

// pages/about.js
import Head from 'next/head';

export default function AboutPage() {
  return (
    <div>
      <Head>
        <title>À Propos - Mon Super Site</title>
      </Head>
      <h1>À Propos de Nous</h1>
      <p>Nous sommes une équipe passionnée dédiée à la création d'applications web exceptionnelles.</p>
    </div>
  );
}

Explication : Ce fichier about.js crée une page accessible via le chemin /about. Il s'agit d'une page statique typique, où le contenu est fixe et ne dépend pas de paramètres d'URL dynamiques.

2. Les Fichiers Spéciaux : _app.js et _document.js

Next.js utilise deux fichiers spéciaux dans le répertoire pages pour des configurations globales :

  • pages/_app.js :

    • Rôle : Ce fichier est le point d'entrée global de votre application. Il initialise toutes vos pages.
    • Utilisation : Vous pouvez l'utiliser pour :
      • Appliquer des mises en page globales (layouts) à toutes vos pages.
      • Maintenir un état global entre les navigations de pages.
      • Charger des feuilles de style globales.
      • Injecter des providers de contexte (par exemple, un thème, une authentification).
    • Important : Le composant exporté par défaut dans _app.js reçoit deux props : Component (la page actuelle à rendre) et pageProps (les props initiales pour cette page).
  • pages/_document.js :

    • Rôle : Ce fichier permet de personnaliser les balises <html> et <body> de votre document HTML côté serveur. Il est rendu une seule fois sur le serveur.
    • Utilisation : Utile pour :
      • Ajouter des meta tags personnalisés (hors de Head spécifique à la page).
      • Charger des polices externes via <link> (comme Google Fonts).
      • Insérer des scripts tiers qui doivent être dans le <body> (par exemple, pour l'analytique).
    • Attention : Ce fichier n'est pas client-side aware. Ne placez pas de logique d'application ou de gestion d'événements React ici.

II. Les Routes Dynamiques

Toutes les pages ne sont pas statiques. Souvent, vous avez besoin de pages qui affichent des contenus différents en fonction d'un identifiant ou d'un "slug" dans l'URL (par exemple, /articles/mon-premier-article ou /users/123). Next.js gère cela avec les routes dynamiques.

1. Création de Routes Dynamiques

Pour créer une route dynamique, vous utilisez des crochets [] autour du nom du fichier ou du dossier. Le nom entre les crochets devient le nom du paramètre accessible dans votre page.

  • Exemple simple : pages/posts/[id].js

    • Cette page répondra à des URLs comme /posts/1, /posts/abc, etc.
    • Le paramètre id sera disponible dans le composant de la page.
  • Exemple imbriqué : pages/blog/[slug]/comments.js

    • Cette page répondra à /blog/mon-article/comments.
    • Le paramètre slug sera disponible.

2. Accéder aux Paramètres de Route avec useRouter

Pour récupérer les valeurs des paramètres de route dynamiques dans votre composant, vous utilisez le hook useRouter de next/router.

Exemple de Code :

// pages/posts/[id].js
import { useRouter } from 'next/router';
import Head from 'next/head';

export default function PostPage() {
  const router = useRouter();
  const { id } = router.query; // Accède au paramètre 'id' de l'URL

  // Si 'id' n'est pas encore défini (pendant le premier rendu client-side)
  if (!id) {
    return <div>Chargement du post...</div>;
  }

  return (
    <div>
      <Head>
        <title>Post n°{id} - Next.js Blog</title>
      </Head>
      <h1>Détail du Post : {id}</h1>
      <p>Ceci est la page pour le post avec l'identifiant {id}.</p>
      {/* Ici, vous feriez généralement un appel API pour récupérer les données du post */}
      <button onClick={() => router.push('/')}>Retour à l'accueil</button>
    </div>
  );
}

Explication :

  1. Nous importons useRouter depuis next/router.
  2. const router = useRouter(); initialise le hook.
  3. const { id } = router.query; extrait le paramètre id de l'objet query. router.query contient un objet avec tous les paramètres de la chaîne de requête et les paramètres de route dynamiques.
  4. La page affiche l'ID récupéré. Vous utiliseriez généralement cet id pour charger des données spécifiques depuis une API ou une base de données.
  5. Le bouton Retour à l'accueil démontre une navigation programmatique simple en utilisant router.push('/').

3. Les Routes "Catch-All" (Attrape-Tout)

Next.js propose également des routes dynamiques "attrape-tout" qui matchent plusieurs segments de chemin. Elles sont définies en utilisant des points de suspension ... à l'intérieur des crochets : [...slug].js.

  • pages/docs/[...slug].js :

    • docs/a -> slug est ['a']
    • docs/a/b -> slug est ['a', 'b']
    • docs/a/b/c -> slug est ['a', 'b', 'c']
  • pages/[[...slug]].js (Catch-all optionnel) :

    • Cette route attrapera les requêtes pour / ainsi que pour /a, /a/b, etc.
    • Utile si votre route dynamique est la route principale et qu'elle peut également fonctionner sans aucun segment (par exemple, un CMS où la page d'accueil est aussi une page de contenu).

III. La Navigation entre les Pages

Une fois vos pages créées, il faut permettre aux utilisateurs de naviguer entre elles. Next.js offre deux mécanismes principaux pour cela : le composant Link et le hook useRouter.

1. Le Composant Link (Client-Side Transitions)

Le composant Link de next/link est la méthode préférée pour naviguer entre les pages internes de votre application. Il offre des avantages significatifs par rapport aux balises <a> HTML standard :

  • Transitions fluides côté client : Au lieu d'un rechargement complet de la page (comme avec <a>), Link effectue une transition côté client, ce qui est beaucoup plus rapide et offre une meilleure expérience utilisateur.
  • Pré-chargement automatique (Prefetching) : Link pré-charge (en arrière-plan) le code et les données des pages vers lesquelles il pointe lorsque le lien devient visible dans le viewport, rendant la navigation quasi instantanée.
  • Accessibilité : Il gère les attributs ARIA nécessaires pour l'accessibilité.

Syntaxe de base :

import Link from 'next/link';

function Navigation() {
  return (
    <nav>
      <Link href="/">
        Accueil
      </Link>
      <Link href="/about">
        À Propos
      </Link>
      <Link href="/posts/123">
        Voir le Post 123
      </Link>
      <Link href="/blog/nouvel-article">
        <span>Lire le blog</span> {/* Peut envelopper d'autres éléments */}
      </Link>
    </nav>
  );
}

Explication : Le composant Link prend une prop href qui spécifie le chemin de la page de destination. Il peut envelopper du texte ou d'autres composants React. Next.js transformera cela en une balise <a> optimisée.

2. Le Hook useRouter (Navigation Programmatique)

Pour des scénarios de navigation plus complexes, comme la redirection après une soumission de formulaire, la navigation conditionnelle ou le retour en arrière, le hook useRouter est votre outil.

Méthodes courantes :

  • router.push(path) : Ajoute une nouvelle entrée à l'historique du navigateur et navigue vers le path spécifié.
  • router.replace(path) : Navigue vers le path spécifié sans ajouter une nouvelle entrée à l'historique (l'entrée actuelle est remplacée). Utile pour des redirections.
  • router.back() : Revient à la page précédente dans l'historique du navigateur.
  • router.reload() : Recharge la page actuelle.

Exemple de Code :

// pages/contact.js
import { useRouter } from 'next/router';
import { useState } from 'react';

export default function ContactPage() {
  const router = useRouter();
  const [message, setMessage] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    // Logique de soumission du formulaire (par ex. appel API)
    console.log('Message envoyé :', message);

    // Redirection vers la page de succès après soumission
    router.push('/success');
    // Ou si vous voulez remplacer l'entrée actuelle de l'historique:
    // router.replace('/success');
  };

  return (
    <div>
      <h1>Contactez-nous</h1>
      <form onSubmit={handleSubmit}>
        <textarea
          value={message}
          onChange={(e) => setMessage(e.target.value)}
          placeholder="Votre message..."
          rows="5"
          cols="50"
        />
        <br />
        <button type="submit">Envoyer le message</button>
      </form>
    </div>
  );
}

Explication : Dans cet exemple, après la soumission du formulaire de contact (simulée par console.log), la fonction router.push('/success') est utilisée pour rediriger l'utilisateur vers une page /success, offrant ainsi une confirmation de l'envoi du message.

IV. Bonnes Pratiques et Optimisations Liées au Routage

  • URLs Sémantiques : Toujours privilégier des URLs claires et descriptives (/blog/mon-super-article plutôt que /blog?id=123). C'est meilleur pour le SEO et l'expérience utilisateur.
  • Gestion des Erreurs 404 : Next.js gère automatiquement les erreurs 404. Si une route n'existe pas, il affichera une page d'erreur par défaut. Vous pouvez personnaliser cette page en créant le fichier pages/404.js.
  • Performance (Prefetching) : Le composant Link précharge automatiquement le code des pages si elles sont visibles à l'écran. Pour des liens qui ne sont pas visibles immédiatement mais que vous savez que l'utilisateur va probablement cliquer, vous pouvez forcer le préchargement avec la prop prefetch sur Link (bien que ce soit rarement nécessaire car la détection automatique est très efficace).
  • Accessibilité : Utilisez toujours le composant Link pour la navigation interne. Il garantit que vos liens sont correctement gérés par les lecteurs d'écran et autres technologies d'assistance.
  • Éviter les rechargements complets : Privilégiez Link ou router.push sur les <a> HTML standard pour la navigation interne afin de bénéficier des avantages du routage côté client de Next.js.

Conclusion

Le système de routage de Next.js est une de ses fonctionnalités les plus puissantes et distinctives. En adoptant une approche basée sur le système de fichiers, il simplifie la création de pages, rend la navigation intuitive et améliore significativement les performances et le SEO de vos applications.

Vous savez maintenant comment :

  • Créer des pages statiques en organisant simplement vos fichiers dans le dossier pages.
  • Mettre en place des routes dynamiques pour gérer des contenus variables.
  • Naviguer entre les pages de manière fluide et performante grâce au composant Link et au hook useRouter.

Maîtriser ces concepts est la pierre angulaire pour construire des applications Next.js robustes et scalables. Dans la prochaine leçon, nous explorerons comment Next.js génère ces pages de manière performante grâce aux méthodes de récupération de données.