Le HTML serveur et le premier rendu React doivent être identiques. Dans Next.js, "use client" n’empêche pas le pré-rendu serveur.
Localiser la première différence
Reproduisez l’erreur avec le serveur de développement et ouvrez la console. Lisez la première erreur et la pile de composants, puis isolez la partie qui diffère. Si le problème n’apparaît qu’en production, reproduisez avec le build de production du projet.
| Cause possible | Exemple | Correction à examiner |
|---|---|---|
| Valeur différente à chaque rendu | Date.now(), Math.random() |
Fournir une valeur initiale stable depuis le serveur |
| Donnée propre au navigateur | localStorage, taille de fenêtre |
Lire après le montage, avec un rendu initial identique |
| Date formatée différemment | Locale ou fuseau implicite | Fixer les paramètres ou formater après le montage |
| HTML invalide | Un div dans un p, des boutons imbriqués |
Corriger la structure que le navigateur répare |
| Données serveur et client différentes | Deux chargements indépendants | Réutiliser le même instantané initial |
| HTML modifié avant React | Extension, CDN ou bibliothèque CSS | Tester sans extension et vérifier la configuration |
Faites un essai avec un profil de navigateur sans extension. Cela aide à distinguer une modification externe d’un bug de l’application.
Lire localStorage après le montage
Un test typeof window !== "undefined" placé dans le rendu peut produire deux contenus différents. Utilisez plutôt une valeur initiale commune, puis lisez le navigateur dans un effet :
"use client";
import { useEffect, useState } from "react";
export default function PreferenceAffichage() {
const [preference, setPreference] = useState("automatique");
useEffect(() => {
try {
const valeur = window.localStorage.getItem("affichage");
if (valeur === "clair" || valeur === "sombre") {
setPreference(valeur);
}
} catch {
// Le stockage peut être bloqué ; la valeur par défaut reste utilisable.
}
}, []);
return <p>Affichage : {preference}</p>;
}
Le serveur et le premier rendu client affichent « automatique ». L’effet applique ensuite la préférence. Ce décalage est adapté à une préférence secondaire ; pour un thème global sans flash, utilisez l’intégration de thème prévue par votre framework plutôt que de masquer toute la page.
Stabiliser les dates et les identifiants
Transmettez une date ISO déjà fixée dans les données initiales. Pour une sortie strictement stable, vous pouvez d’abord afficher cette même chaîne :
export function DatePublication({ iso }: { iso: string }) {
return <time dateTime={iso}>{iso}</time>;
}
Formatez-la ensuite selon les besoins : sur le serveur avec une chaîne transmise telle quelle, ou après montage pour respecter le fuseau du visiteur. Ne générez pas une nouvelle date indépendamment à chaque rendu.
Pour relier les champs et leurs labels, useId fournit des identifiants compatibles avec le rendu serveur lorsque l’arbre de composants correspond. Pour les clés de liste, utilisez l’identifiant stable des données ; useId n’est pas destiné à remplacer ces clés.
Isoler une bibliothèque qui exige le navigateur
Dans Next.js, si un widget ne peut réellement pas fonctionner au serveur, un Client Component peut le charger sans SSR :
"use client";
import dynamic from "next/dynamic";
const Carte = dynamic(() => import("./Carte"), {
ssr: false,
loading: () => <p>Chargement de la carte…</p>,
});
export default function CarteClient() {
return <Carte />;
}
Le fichier Carte doit exister et exporter le composant par défaut. Avec l’App Router, ssr: false doit être placé dans un Client Component. Réservez cette approche au widget concerné : son contenu n’est plus fourni dans le HTML serveur.
Vérifier la correction
Rechargez directement la page, puis testez la navigation interne, une session sans stockage et les préférences déjà enregistrées. Vérifiez l’absence d’erreur et le bon fonctionnement des interactions, pas seulement l’apparence.
suppressHydrationWarning est une exception locale pour une différence inévitable, limitée à un niveau. Ce n’est pas une réparation du rendu. Retirer le SSR de toute la page ou repousser tout son contenu au montage peut cacher la cause et dégrader le chargement.

