Leçon 7 / 20

Mettre en cache les lectures

20 min Next.js — données, formulaires et cache Gratuit

Objectif : Configurer la mise en cache des lectures du catalogue avec une durée de revalidation adaptée à la fréquence de mise à jour des données.

Une page de catalogue peut déclencher de nombreuses lectures identiques de l’API, alors que les randonnées ne changent pas à chaque visite. Sans stratégie de cache, ces requêtes répétées sollicitent inutilement la source de données. Vous allez définir une durée de revalidation pour réutiliser les réponses récentes, sans empêcher leur actualisation.

Choisir la durée de revalidation

La fonction serveur obtenirRandonnees effectue déjà la requête de données et vérifie que la réponse HTTP est valide, comme vu dans les leçons précédentes. Pour contrôler la durée de conservation de cette réponse par Next.js, vous passez l’option next: { revalidate: nombre } au deuxième argument de fetch. La durée est exprimée en secondes : 300 demande une revalidation au bout de cinq minutes.

Configurer le chargement du catalogue

Dans la version suivante de app/page.tsx, la lecture est conservée côté serveur et la seule modification liée au cache est l’option passée à fetch. La valeur de CATALOGUE_API_URL reste une configuration serveur. L’URL de la requête reçoit le filtre uniquement s’il correspond à l’une des difficultés autorisées.

app/page.tsxTexte
type Difficulte = 'facile' | 'intermediaire' | 'difficile';

type Randonnee = {
  id: string;
  nom: string;
  difficulte: Difficulte;
  distance: number;
};

const difficultesAutorisees: Difficulte[] = [
  'facile',
  'intermediaire',
  'difficile'
];

async function obtenirRandonnees({ difficulte }: { difficulte?: string }) {
  const url = new URL('/randonnees', process.env.CATALOGUE_API_URL);

  if (difficulte && difficultesAutorisees.includes(difficulte as Difficulte)) {
    url.searchParams.set('difficulte', difficulte);
  }

  const reponse = await fetch(url, {
    next: { revalidate: 300 }
  });

  if (!reponse.ok) {
    throw new Error('Impossible de charger les randonnées.');
  }

  return await reponse.json() as Randonnee[];
}

export default async function CataloguePage({
  searchParams
}: {
  searchParams: Promise<{ difficulte?: string }>;
}) {
  const { difficulte } = await searchParams;
  const difficulteValidee = difficulte && difficultesAutorisees.includes(difficulte as Difficulte)
    ? difficulte
    : undefined;
  const randonnees = await obtenirRandonnees({ difficulte: difficulteValidee });

  return (
    <>
      <h1 className="rando-titre">Randonnées à découvrir</h1>
      <form className="rando-recherche" action="/">
        <label htmlFor="difficulte">Difficulté</label>
        <select id="difficulte" name="difficulte" defaultValue={difficulteValidee ?? ''}>
          <option value="">Toutes</option>
          <option value="facile">Facile</option>
          <option value="intermediaire">Intermédiaire</option>
          <option value="difficile">Difficile</option>
        </select>
        <button className="rando-bouton" type="submit">Rechercher</button>
      </form>
      {randonnees.length === 0 ? (
        <p className="rando-etat" role="status">Aucune randonnée ne correspond à cette recherche.</p>
      ) : (
        <ul className="rando-liste">
          {randonnees.map((randonnee) => (
            <li className="rando-carte" key={randonnee.id}>
              <a href={`/randonnees/${randonnee.id}`}>
                <h2>{randonnee.nom}</h2>
                <p>{randonnee.difficulte} · {randonnee.distance} km</p>
              </a>
            </li>
          ))}
        </ul>
      )}
    </>
  );
}

La page transmet le paramètre validé à la fonction d’accès aux données ; la fonction construit ensuite la requête filtrée et applique la même règle de cache à cette lecture. Ainsi, les réponses correspondant à des filtres différents peuvent être traitées comme des requêtes distinctes. L’interface conserve le filtre sélectionné dans le formulaire GET, et les données ne sont pas chargées depuis le navigateur.

Vérifier le résultat et les limites

Avec revalidate: 300, Next.js peut servir une réponse mise en cache pendant la durée définie et la revalider ensuite selon sa stratégie de cache. Le résultat visible reste une liste de randonnées ; cette option ne modifie ni son format ni le rendu du formulaire. Si l’API renvoie un statut d’échec, la fonction lève toujours une erreur : une réponse en cache n’est pas une raison pour traiter une défaillance comme une liste vide.

À retenir

  • Configurez la durée de revalidation sur le fetch serveur qui lit les données.
  • La valeur de revalidate s’exprime en secondes ; choisissez-la selon la fréquence de mise à jour attendue.
  • Le filtre validé fait partie de l’URL de requête : chaque variante de recherche peut produire une réponse distincte.
  • Conservez la vérification du statut HTTP et la propagation des erreurs, même lorsque les réponses sont mises en cache.

Dans la prochaine leçon, vous chargerez une randonnée précise à partir de son identifiant dans une route de détail.

Envie d'aller plus loin ?

Les cours Enovatic sont gratuits et le resteront. Si vous cherchez un accompagnement encadré, nos formations professionnelles sont animées par les mêmes formateurs.