Hydration mismatch in React: i bug che compaiono solo quando aggiungi SSR

Tema, localStorage, date e rendering deterministico: quattro lezioni pratiche.

L'hydration mismatch è uno di quei problemi che puoi non incontrare mai finché React renderizza tutto nel browser.

Con SSR, invece, il browser riceve HTML prodotto altrove e React deve riuscire a ricostruire esattamente lo stesso albero al primo render.

Che cos'è davvero l'hydration

Il server genera markup statico. Nel browser React non dovrebbe ricrearlo da zero: deve agganciarsi a quell'HTML, collegando stato ed eventi.

Se però il primo render client produce un risultato differente, React segnala un mismatch e può essere costretto a scartare parte del markup server-side.

Caso 1: localStorage nel primo render

Il server non ha localStorage. Il browser sì.

Se un componente usa una preferenza salvata per decidere immediatamente cosa renderizzare, server e client possono partire da due stati differenti.

Un theme switcher è l'esempio perfetto: il server può assumere il tema di sistema, mentre il browser conosce già la scelta dell'utente.

La soluzione: primo render deterministico

La strategia è semplice: il primo render client deve usare lo stesso valore del server. Solo dopo il mount si leggono preferenze locali e si aggiorna lo stato.

Questo può introdurre una piccola fase di sincronizzazione, ma evita di rompere l'hydration dell'intera pagina.

Caso 2: il fuso orario

Questo bug è più subdolo perché non coinvolge API browser.

Una data formattata con le impostazioni locali del processo può produrre risultati differenti se Node gira in UTC e il browser usa un altro fuso.

Vicino alla mezzanotte la differenza può diventare visibile: il server mostra un giorno, il browser quello successivo.

Caso 3: contenuto dipendente dall'ambiente

Lo stesso rischio esiste con:

  • window.innerWidth;
  • matchMedia();
  • lingua del browser;
  • cookie letti soltanto lato client;
  • Date.now();
  • valori casuali.

Tutto ciò che può produrre valori differenti tra server e browser va trattato con attenzione.

useEffect non è il nemico

Il problema non è usare API browser in assoluto. È usarle durante il render iniziale.

Un accesso a window dentro un useEffect che gira dopo l'hydration è normalmente sicuro. Un accesso dentro l'inizializzatore di uno useState può invece modificare immediatamente il markup.

Come testare i mismatch

Un test puramente unitario non basta sempre. Serve almeno una prova che confronti il comportamento server/client e, idealmente, un browser reale automatizzato.

Un buon controllo consiste nel:

  1. generare l'HTML via SSR;
  2. caricare quella pagina in un browser;
  3. impostare stati realistici, come preferenze salvate;
  4. controllare console error e warning durante l'hydration.

Conclusione

L'hydration mismatch non è un difetto misterioso di React. Quasi sempre rivela una cosa precisa: il primo render dipende da informazioni che server e browser non condividono.

SSR costringe quindi a distinguere nettamente tra stato necessario a costruire l'HTML iniziale e stato che può essere applicato successivamente.

Condividi: