Stratégies Avancées de Rendu et de Récupération de Données dans Next.js

Introduction aux Stratégies de Données et de Rendu

1. getStaticPaths : Génération des Chemins Statiquees Dynamiques

Cette fonction est essentielle pour définir les chemins dynamiques qui doivent être pré-rendus au moment de la construction pour une application SSG.

// Exemple: pages/blog/[articleId].js
export async function getStaticPaths() {
  return {
    paths: [
      // 1. Format de paramètre basique: pages/blog/[articleId].js → blog/premier-article
      { params: { articleId: 'premier-article' } },
      // 2. Routage dynamique imbriquée: pages/[category]/[slug].js → technologies/nextjs-guide
      { params: { category: 'technologies', slug: 'nextjs-guide' } },
      // 3. Chemin générique facultatif (catch-all): pages/[...pathSegments].js → docs/library/api
      { params: { pathSegments: ['docs', 'library', 'api'] } },
    ],
    // Option de repli (fallback), obligatoire parmi les trois suivantes :
    fallback: false,    // Option 1: Seuls les chemins listés sont générés, les autres mènent à une 404.
    fallback: true,     // Option 2: Permet la génération incrémentale, affiche un état de chargement.
    fallback: 'blocking' // Option 3: Génération incrémentale, bloque la requête jusqu'à ce que la page soit prête.
  };
}

Détails des paramètres : Le contexte d'entrée est généralement vide, mais peut inclure des informations de localisation telles que locales (liste des langues supportées) et defaultLocale (langue par défaut), bien que moins utilisées dans le Pages Router.

2. getStaticProps : Récupération des Propriétés de Page pour SSG

Utilisée pour acquérir les données nécessaires à une page lors de la phase de compilation.

export async function getStaticProps(fetchContext) {
  // fetchContext.params contient les paramètres de routage dynamique.
  const { params } = fetchContext;
  
  // Simulation de récupération de données pour un article spécifique
  const articleData = { id: params.articleId, title: 'Titre de l\'article' };

  return {
    props: {
      // Les données sont injectées dans le composant de la page.
      data: articleData,
    },
    revalidate: 120, // Clé de l'ISR (Incremental Static Regeneration) : revalidation après 120 secondes.
    notFound: false, // Si défini à true, renvoie une page 404.
    redirect: {
      destination: '/nouvelle-destination',
      permanent: false, // true pour 308 (permanent), false pour 307 (temporaire).
    }
  };
}

Caractéristiques clés :

  • Un seul parmi props, notFound, ou redirect doit être retourné.
  • Le paramètre revalidate est crucial pour l'ISR.
  • Pour le SEO, utilisez permanent: true (code 308) pour les redirections définitives et permanent: false (code 307) pour les temporaires.
  • Une page notFound personnalisée offre une meilleure expérience utilisateur qu'une erreur générique.

3. getServerSideProps : Récupération des Données en Temps Réel pour SSR

Cette fonction récupère les données les plus récentes à chaque requête entrante.

export async function getServerSideProps({ request, response, urlParams, queryParams, currentLocale }) {
  // Description des paramètres :
  // request → Objet de requête HTTP (inclut cookies, en-têtes, etc.)
  // response → Objet de réponse HTTP (permet de définir en-têtes, cookies, etc.)
  // urlParams.articleId → Issu de l'URL : /articles/unique-id-123
  // queryParams → Issu des paramètres de requête URL : /articles?format=json
  // currentLocale → Déduit de l'en-tête Accept-Language ou de l'URL
  
  // Exemple de récupération de données dynamique basée sur la requête
  const dynamicContent = await fetch(`https://api.example.com/data?id=${urlParams.articleId}`);
  const jsonData = await dynamicContent.json();

  return {
    props: {
      // Les données sont injectées dans le composant de la page.
      serverData: jsonData,
    }
    // Note : Le paramètre 'revalidate' n'est pas disponible ici.
  };
}

Comparaison des Stratégies de Rendu

Stratégie Indicateur Clé Cas d'Usage Recommandé
SSG getStaticProps() sans revalidate Pages avec contenu statique ou peu changeant (ex: documentation, blog post classique)
ISR getStaticProps() + revalidate Contenu mis à jour fréquemment mais non en temps réel (ex: actualités, fiches produit)
SSR getServerSideProps() Contenu personnalisé ou données nécessitant une fraîcheur absolue à chaque requête (ex: tableaux de bord utilisateur, résultats de recherche)
CSR useEffect() / useSWR() côté client Données fortement interactives ou spécifiques à l'utilisateur après le chargement initial de la page (ex: filtres, recherche instantanée)

Les approches SSG et SSR génèrent une HTML complète côté serveur, nécessitant une étape d'hydratation côté client pour devenir interactives. Par contraste, l'import dynamique de composants avec dynamic de Next.js permet à React de rendre d'abord un élément de substitution (loading) et de remplacer ensuite ce contenu par le composant réel une fois son bundle JS téléchargé, ce qui est plus proche d'une approche CSR sans hydratation.

Import Dynamique et Segmentation du Code

import dynamic from 'next/dynamic';

const DynamicContentModule = dynamic(
  () => import('../components/HeavyComponent'),
  {
    ssr: true, // Valeur par défaut : le composant est chargé côté serveur.
    loading: () => <p>Chargement du module...</p>
  }
);

Fonctionnalités essentielles :

  • Le paramètre ssr est par défaut à true, ce qui signifie que le composant est pré-rendu sur le serveur.
  • L'objectif principal est la segmentation du code (code splitting) : les composants importés via dynamic sont regroupés dans des bundles JS distincts, chargés uniquement quand nécessaire.
  • Contrairement à un import classique, qui inclut le composant dans le bundle principal, dynamic permet un chargement à la demande, améliorant les performances initiales.
  • Le rendu initial affiche un indicateur de chargement (loading) avant que le composant réel ne soit monté, similaire à une stratégie CSR où l'interactivité est immédiate sans phase d'hydratation.

Fonctionnalités d'Optimisation Intégrées

1. Optimisation des Images

  • Next.js offre une optimisation automatique (redimensionnement, formatage, chargement paresseux) via le composant Image.
  • Supporte des formats modernes comme WebP.
  • Aide à prévenir les décalages de mise en page (CLS).

2. Optimisation des Polices

  • Optimisation et préchargement automatiques des polices.
  • Réduit également le CLS.

3. Optimisation des Scripts

  • Permet d'optimiser le chargement de scripts tiers.
  • Supporte l'attribut strategy (beforeInteractive, afterInteractive, lazyOnload) pour contrôler le moment du chargement.

Le Système de Routage

1. Le Routage par Fichiers (Pages Router)

  • Un système de routage basé sur la structure des fichiers du répertoire pages/.
  • Prend en charge les routes dynamiques : [id].js, [...slug].js.
  • Permet le routage imbriqué via des sous-dossiers.

2. Le Routage Superficiel (Shallow Routing)

import { useRouter } from 'next/router';

const MyComponent = () => {
  const navigationController = useRouter();

  const navigateWithShallow = () => {
    navigationController.push(
      '/products?category=electronics&page=2',
      undefined, 
      { shallow: true } // Le paramètre clé
    );
  };

  // ...
};

Scénarios d'utilisation : Filtrage, tri, pagination, changement d'onglet, où seule l'URL doit être mise à jour sans recharger la page.

  • Navigation classique : Modification de l'URL → nouvelle récupération de données → nouveau rendu du composant.
  • Navigation superficielle : Modification de l'URL → mise à jour directe de l'URL → maintien de l'état actuel du composant.

Le routage superficiel est idéal pour les situations où seuls les paramètres de requête changent et le contenu de la page peut être mis à jour par la logique côté client. Cette fonctionnalité est moins courante avec l'adoption progressive du App Router.

3. Les Routes d'API

  • Tout fichier placé dans le répertoire pages/api/ agit comme un point d'accès API côté serveur.
  • Ces fonctions reçoivent des objets req (requête) et res (réponse) pour gérer les échanges.
  • Cette fonctionnalité transforme Next.js d'un simple framework frontal en une solution full-stack complète.

4. Les Middlewares

  • Historiquement, les middlewares étaient définis dans un fichier _middleware.js au sein du répertoire pages/.
  • La pratique recommandée actuelle est de créer un fichier middleware.js à la racine du projet.

L'App Router (Approche Moderne)

L'App Router représente la solution la plus récente et recommandée pour Next.js, offrant des avantages significatifs en termes de performance, notamment via l'hydratation sélective. Seuls les composants marqués avec 'use client' sont hydratés.

1. Simplification de la Récupération de Données

  • getStaticProps est remplacé par l'utilisation directe de fonctions asynchrones dans les composants (par défaut SSG avec cache).
  • getStaticPaths est remplacé par generateStaticParams.
export async function generateStaticParams() {
  return [{ slug: 'premier-produit' }, { slug: 'second-produit' }];
}
export const dynamicParams = true; // Équivalent à fallback: true
    
  1. L'équivalent de getServerSideProps est obtenu en :
import { unstable_noStore } from 'next/cache';
export const dynamic = 'force-dynamic'; // Force le rendu dynamique à chaque requête.
// Alternativement, utiliser l'option cache: 'no-store' sur les requêtes fetch.
// Ou déclencher un rendu dynamique avec des fonctions comme cookies() ou headers().
   

2. API de Métadonnées

  • La fonction generateMetadata permet de générer dynamiquement des métadonnées pour un SEO amélioré.

3. Implémentation d'ISR

export const revalidate = 90; // La page sera revalidée toutes les 90 secondes.
// Ou, pour une requête fetch spécifique :
fetch(url, { next: { revalidate: 90 } });

4. Composants Client

  • Nécessitent la directive explicite 'use client' au début du fichier.
  • L'App Router effectue une hydratation partielle par défaut : les composants serveur ne sont pas hydratés, seuls les composants client le sont.

Conditions d'hydratation :

  1. Le composant est marqué 'use client' (indiquant qu'il requiert de l'interactivité).
  2. Le composant a été pré-rendu en HTML côté serveur (par défaut ou si ssr: true pour les imports dynamiques).

Cas sans hydratation :

  1. Composants Serveur (sans 'use client').
  2. Composants Client avec ssr: false dans un import dynamique.
  3. Composants purement CSR (aucun rendu initial côté serveur).

5. Optimisation de l'Import Dynamique

dynamic(() => import('../components/LargeClientComponent'), { ssr: false }) // Utilisé principalement pour un chargement différé.

6. Rendu en Streaming

  • L'App Router prend en charge nativement le rendu en streaming.
  • Nécessite l'utilisation du composant <Suspense> pour encapsuler le contenu asynchrone.
  • Chaque limite de <Suspense> permet un streaming indépendant.

7. Server Actions

  • Fonctions déclarées avec la directive 'use server'.
  • Elles encapsulent une communication réseau, offrant une expérience de "fonction locale" pour les appels côté serveur.
  • Simplifient le traitement des formulaires et réduisent la nécessité de créer des routes API complexes pour des opérations simples.

8. Autres Fonctionnalités Clés

  • Middleware : Défini dans middleware.js à la racine du projet, pour l'authentification, l'internationalisation, les redirections, etc.

  • Groupes de Routes : Utilisation de parenthèses ( ) autour des noms de dossiers pour organiser la structure de fichiers sans impacter l'URL.

  • Cookies/Headers : Accès aux informations de requête via les fonctions cookies() et headers() dans les composants serveur.

  • Routes Interceptrices : Utilisation du préfixe (.) pour intercepter une route dans le même répertoire, souvent pour afficher des modales.

  • Navigation Côté Client :

    • usePathname : Récupère le chemin URL actuel.
    • useSearchParams : Accède aux paramètres de requête URL.
    • useRouter : Permet de manipuler la navigation.

    Note : Ces hooks doivent être utilisés dans des composants client ('use client') et usePathname/useSearchParams peuvent déclencher un rendu dynamique.

Synthèse et Recommandations

Conseils de Développement

  1. Composants interactifs : Utilisez 'use client'.
  2. Composants à chargement différé : Employez dynamic.
  3. Contenu à mise à jour régulière : Configurez revalidate.
  4. Gestion simplifiée des données côté client : Considérez useSWR.

Choix de la Stratégie de Rendu

  • Pages statiques simples : Adoptez le SSG par défaut de l'App Router.
  • Données en temps réel : Utilisez dynamic = 'force-dynamic' ou unstable\_noStore().
  • Contenu mis à jour fréquemment : Implémentez l'ISR (revalidate).
  • Données fortement interactives côté utilisateur : Privilégiez le CSR (useEffect/useSWR).

Étiquettes: Next.js Server-Side Rendering Static Site Generation Incremental Static Regeneration App Router

Publié le 21 juillet à 14h54