Početna
» Osnovno znanje
»
Kako riješiti grešku "Hydration failed because the initial UI does not match"
Kako riješiti grešku "Hydration failed because the initial UI does not match"
Željeni rezultat jednostavno je opisati: HTML generiran na poslužitelju mora odgovarati onome što React generira pri prvom prikazu u pregledniku. Kada je to točno, React može dodati rukovatelje događajima i učiniti stranicu interaktivnom bez bacanja greške pri hidrataci, zamjene podstabla ili prikaza neočekivanog vizualnog skoka.
Hidratacija je proces u kojem React preuzima HTML koji je već prikazan na poslužitelju i dodaje mu React ponašanje u pregledniku. Trenutna dokumentacija za hydrateRoot navodi da se očekuje da sadržaj prikazan na klijentu bude identičan sadržaju prikazanom na poslužitelju te da se neslaganja trebaju tretirati kao greške.
Točan tekst greške mijenjao se kroz različita izdanja Reacta i okvira. Možda ćete vidjeti stariju poruku poput "Hydration failed because the initial UI does not match what was rendered on the server" ili noviju poruku koja objašnjava da stablo prikazano na poslužitelju ne odgovara onome na klijentu. Princip otklanjanja grešaka ostaje isti.
Kontekst verzije je važan. Na dan 11. rujna 2026., službena stranica Reacta navodi React 19.3 kao najnoviju verziju Reacta, dok trenutna dokumentacija Next.js-a identificira Next.js 16.3.4 kao najnovije izdanje Next.js-a. Provjerite stranicu s verzijama Reacta i trenutnu dokumentaciju Next.js-a ako ovo čitate kasnije, jer se dostupni API-ji i poruke o greškama mogu promijeniti.
Ilustracija generirana AI-em: Počnite lociranjem prve komponente navedene u grešci pri hidrataci i potvrdom da se problem javlja pri svježem učitavanju stranice. Ovo nije stvarni snimak zaslona preglednika, Reacta ili Next.js-a; koristite provjerene veze na kod i dokumentaciju u članku kao izvor istine.
Što se smatra uspješnim popravkom?
Nemojte procjenjivati uspjeh samo na temelju nestanka crvenog razvojnog sloja. Dobar popravak trebao bi zadovoljiti nekoliko provjera:
Upozorenje ili greška pri hidrataci više se ne pojavljuju pri čistom ponovnom učitavanju.
Početni korisnički sučelje prikazano na poslužitelju i prvi React prikaz u pregledniku predstavljaju isti sadržaj i strukturu.
Pogođena komponenta ostaje interaktivna nakon hidratacije.
Ne postoji očiti bljesak s jedne vrijednosti na drugu, osim ako ta promjena nije namjerna i dizajnirana.
Problem ostaje riješen u produkcijskoj verziji, a ne samo u razvojnom poslužitelju.
Ispravili ste uzrok, a ne sakrili stvarno neslaganje opcijom za suzbijanje upozorenja.
Ako upozorenje nestane, ali stranica sada prikazuje važan sadržaj tek nakon što se JavaScript učita, greška možda više ne postoji, ali je korisničko iskustvo postalo lošije. To može biti razuman kompromis za widget koji radi samo u pregledniku, ali nije automatski najbolji rezultat za glavni sadržaj stranice.
Korak 1: Reproducirajte neslaganje i pronađite najmanju komponentu koja ne uspijeva
Počnite s tvrdim ponovnim učitavanjem u razvojnom okruženju i pročitajte cijelu grešku, uključujući stog komponenti. Dokumentirana greška pri hidrataci u Reactu 19 navodi nekoliko čestih uzroka: grane poslužitelja/klijenta poput typeof window !== 'undefined', promjenjive vrijednosti poput Date.now() ili Math.random(), formatiranje datuma ovisno o lokalizaciji, vanjski podaci koji su se promijenili bez snimke, neispravno ugniježđenje HTML-a i proširenja preglednika koja mijenjaju DOM. Pogledajte React grešku 418.
Next.js daje sličan popis u svom službenom vodiču za greške pri hidrataci, dodajući API-je dostupne samo u pregledniku poput window i localStorage, konfiguraciju CSS-in-JS-a i HTML izmijenjen od strane Edge/CDN sloja.
Ilustracija generirana AI-em: Sužite grešku na izraz koji može proizvesti različitu vrijednost na poslužitelju i u pregledniku, poput datuma, nasumičnog broja, lokalizacije ili vrijednosti izvedene iz preglednika. Ovo nije stvarni snimak zaslona preglednika, Reacta ili Next.js-a; koristite provjerene veze na kod i dokumentaciju u članku kao izvor istine.
Praktična metoda izolacije je privremena zamjena sumnjivih dinamičkih sekcija determinističkim tekstom. Ako greška nestane, vraćajte te sekcije jednu po jednu. To je obično brže od mijenjanja globalnih postavki prikaza prije nego što znate koja je komponenta odgovorna.
Signal kvalitete
Spremni ste za nastavak kada možete imenovati i komponentu koja ne uspijeva i vrijednost ili strukturu koja se razlikuje. "Događa se negdje u nadzornoj ploči" je još uvijek preširoko. "Vremenska oznaka u StatusCard generira se neovisno na poslužitelju i klijentu" je djelotvorno.
Korak 2: Uklonite nedeterminističke vrijednosti iz početnog prikaza
Deterministički prikaz znači da isti ulazi proizvode isto početno korisničko sučelje. Vrijednosti koje se neovisno mijenjaju između prikaza na poslužitelju i prikaza u pregledniku česti su izvori neslaganja.
Razmislite o ovom problematičnom obrascu:
export default function LastUpdated() {
return <time>{new Date().toLocaleString()}</time>;
}
Poslužitelj i preglednik mogu izvršiti ovaj kod u različitim trenucima i u različitim lokalizacijama ili vremenskim zonama. Bolje rješenje ovisi o tome što stranica treba komunicirati.
Ako vremenska oznaka predstavlja podatke s poslužitelja, izračunajte ili dohvatite je jednom na poslužitelju i proslijedite istu serijaliziranu vrijednost klijentu:
Ako vrijednost doista ovisi o pregledniku korisnika, prvo prikažite stabilni rezervni sadržaj (placeholder) i ažurirajte ga nakon hidratacije.
Ilustracija generirana AI-em: Stabilna početna vrijednost može se čisto hidratizirati, a zatim se sadržaj specifičan za preglednik može primijeniti nakon što se komponenta montira. Ovo nije stvarni snimak zaslona preglednika, Reacta ili Next.js-a; koristite provjerene veze na kod i dokumentaciju u članku kao izvor istine.
Ovo funkcionira jer poslužitelj i prvi prikaz na klijentu oba proizvode isti rezervni sadržaj. Reactova dokumentacija za useEffect opisuje ovaj dvostupanjski obrazac za rijetke slučajeve kada sadržaj na klijentu mora biti različit od sadržaja na poslužitelju.
Kada promijeniti pristup
Ako je vrijednost dostupna samo u pregledniku cijela svrha komponente – na primjer, uređivač vraćen iz localStorage ili widget koji se ne može smisleno prikazati na poslužitelju – prisiljavanje obrasca rezervnog sadržaja i efekta kroz cijelu komponentu može dodati nepotrebnu složenost. U tom slučaju, umjesto pretvaranja da je komponenta moguća za prikaz na poslužitelju, koristite namjernu granicu samo za preglednik.
Korak 3: Ne čitajte API-je dostupne samo u pregledniku tijekom prvog prikaza kompatibilnog s poslužiteljem
Uobičajena zabluda u Next.js-u je da dodavanje 'use client' jamči da se komponenta prikazuje samo u pregledniku. Ne jamči. Next.js objašnjava da su klijentske komponente granica za stanje, efekte, rukovatelje događajima i API-je preglednika, ali klijentske komponente i dalje mogu sudjelovati u predprikazivanju. Pogledajte trenutnu dokumentaciju za use client.
Na poslužitelju, localStorage ne postoji. Čak i grana poput typeof window !== 'undefined' može proizvesti različiti markup pri prvom prikazu u pregledniku, što i React i Next.js dokumentiraju kao uzrok neslaganja pri hidrataci.
Za male razlike, premjestite čitanje iz preglednika u Effect. Za komponentu koja bi u Next.js-u trebala biti doista samo za preglednik, možete je dinamički učitati s onemogućenim SSR-om:
Ilustracija generirana AI-em: Koristite granicu samo za klijenta za komponente koje temeljno ovise o API-jima preglednika, umjesto da dopustite da poslužitelj i preglednik prikažu različita stabla. Ovo nije stvarni snimak zaslona preglednika, Reacta ili Next.js-a; koristite provjerene veze na kod i dokumentaciju u članku kao izvor istine.
Next.js dokumentira ssr: false za klijentske komponente u svom vodiču za ljenčavo učitavanje. Isti vodič navodi da ssr: false nije podržan kada pokušavate koristiti tu opciju izravno u komponenti poslužitelja; premjestite dinamički uvoz u klijentsku komponentu.
React 19.3: prvorazredna opcija samo za preglednik
React 19.3 uveo je browser API. Komponenta može pozvati use(browser()) unutar Suspense granice kako bi isključila tu komponentu iz prikaza na poslužitelju. Poslužitelj prikazuje Suspense rezervni sadržaj, dok se komponenta normalno prikazuje u pregledniku. Pogledajte referencu za browser API Reacta.
import { Suspense, use } from 'react';
import { browser } from 'react-dom';
function BrowserOnlyContent() {
use(browser('Requires browser APIs'));
return <ActualBrowserContent />;
}
export default function Example() {
return (
<Suspense fallback={<p>Loading...</p>}>
<BrowserOnlyContent />
</Suspense>
);
}
U aplikaciji s React Server Components, React navodi da se use(browser()) mora pozvati iz klijentske komponente. Također provjerite izlaže li vaš okvir i instalirana verzija Reacta ovaj API prije nego što ga usvojite.
Korak 4: Učinite podatke s poslužitelja i prve podatke na klijentu istom snimkom
Snimka je točno stanje podataka korišteno za generiranje početnog HTML-a. Hidratacija postaje krhka ako poslužitelj prikaže jednu verziju podataka, a klijent odmah pročita noviju ili drugačije poredanu verziju prije nego što hidratacija završi.
Ilustracija generirana AI-em: Prvi prikaz na klijentu trebao bi konzumirati istu početnu snimku podataka koja je proizvela HTML s poslužitelja; kasnija ažuriranja mogu se dogoditi nakon hidratacije. Ovo nije stvarni snimak zaslona preglednika, Reacta ili Next.js-a; koristite provjerene veze na kod i dokumentaciju u članku kao izvor istine.
Na primjer, pretpostavimo da poslužitelj prikaže cijenu od 99 USD, ali klijent odmah dohvati isti proizvod i dobije 109 USD prije svog prvog prikaza. Problem nije u tome što su se podaci promijenili; promjena podataka je normalna. Problem je u tome što su dva okruženja koristila različite početne ulaze.
Snažan obrazac je:
Dohvatite početne podatke na poslužitelju.
Prikažite HTML iz tih podataka.
Proslijedite ili serijalizirajte iste početne podatke u klijentsku komponentu.
Nakon hidratacije, dopustite klijentu da revalidira i ažurira ako postoje noviji podaci.
Točna implementacija ovisi o modelu dohvaćanja podataka vašeg okvira, ali kriterij kvalitete ostaje isti: HTML s poslužitelja i prvo stablo na klijentu trebali bi se temeljiti na istom logičkom stanju.
Kada promijeniti pristup
Ako je sadržaj inherentno u stvarnom vremenu i zastarjela snimka s poslužitelja mogla bi zavarati korisnike – na primjer, widget za trgovanje u stvarnom vremenu ili brzo mijenjajuća se operativna konzola – razmislite o prikazivanju stabilne ljuske na poslužitelju i učitavanju živog dijela na klijentu. To odriče dio sadržaja prikazanog na poslužitelju za tu regiju, ali može biti iskrenije od hidratacije prema podacima za koje je zajamčeno da će se promijeniti.
Korak 5: Ispravite neispravan HTML prije nego što okrivite React
Preglednici smiju ispravljati neispravan ili neispravno ugniježđen HTML. To ispravljanje može proizvesti DOM strukturu koja se razlikuje od strukture koju React očekuje, čak i kada je JSX izgledao vizualno vjerodostojno.
Ilustracija generirana AI-em: Provjerite semantičko ugniježđenje HTML-a kada stablo komponenti izgleda deterministički, ali preglednik i dalje konstruira drugačiji DOM. Ovo nije stvarni snimak zaslona preglednika, Reacta ili Next.js-a; koristite provjerene veze na kod i dokumentaciju u članku kao izvor istine.
Next.js izričito navodi primjere poput <div> unutar <p>, liste unutar odlomka, ugniježđenih sidara i ugniježđenih gumba kao uzroke problema s hidratacijom.
Na primjer, izbjegavajte:
<p>
Intro text
<div>Details</div>
</p>
Umjesto toga koristite ispravnu strukturu:
<div>
<p>Intro text</p>
<div>Details</div>
</div>
Ako biblioteka komponenti generira markup, pregledajte konačni DOM umjesto da pretpostavljate da su omotači ispravni. Pravilo lintanja ili validator HTML-a mogu pomoći, ali stvarni DOM preglednika je ono što React hidratizira.
Korak 6: Isključite kod izvan komponente
Ako je vaša logika prikaza deterministička i vaš HTML ispravan, provjerite mijenja li nešto HTML s poslužitelja prije nego što ga React hidratizira.
Službena dokumentacija Next.js-a navodi nekoliko mogućnosti:
Proširenje preglednika mijenja stranicu prije nego što se React učita.
Biblioteka CSS-in-JS-a neispravno je konfigurirana za prikaz na poslužitelju.
Značajka Edge ili CDN-a prepisuje ili minificira HTML odgovor.
Na iOS-u, automatsko otkrivanje brojeva telefona, e-pošte, datuma ili adresa može u nekim slučajevima pretvoriti tekst u veze.
Koristite kontrolirane usporedbe. Testirajte u privatnom prozoru preglednika s onemogućenim proširenjima. Ako se greška javlja samo iza CDN-a, usporedite s odgovorom izvora. Ako je počela nakon usvajanja biblioteke za stiliziranje, slijedite službenu SSR konfiguraciju te biblioteke umjesto primjene generičkog zaobilaznog rješenja za hidrataciju.
Signal kvalitete
Izolirali ste ovu klasu problema kada se ista verzija aplikacije ispravno hidratizira u jednom kontroliranom okruženju, ali ne uspijeva nakon što specifično proširenje preglednika, proxy, CDN transformacija ili integracija promijeni HTML.
Korak 7: Koristite suppressHydrationWarning samo za doista neizbježnu lokalnu razliku
React pruža suppressHydrationWarning={true} za rijetke slučajeve kada tekst ili atributi jednog elementa ne mogu razumno odgovarati, poput određenih vremenskih oznaka.
Ovo nije opći mehanizam popravka. Reactova dokumentacija o zajedničkim DOM svojstvima navodi da opcija djeluje samo jednu razinu duboko i namijenjena je kao izlazna vrata. Vodič za hidrataciju Next.js-a također upozorava da React neće pokušati zakrpati neslaganja u tekstualnom sadržaju kada se ova opcija koristi.
Koristite je samo kada su sve ove tvrdnje točne:
Razlika je očekivana i lokalizirana.
Neslaganje ne predstavlja netočno stanje aplikacije.
Okolna struktura je stabilna.
Svjesno ste prihvatili da se početna vrijednost s poslužitelja i vrijednost preglednika razlikuju.
Ako dodavanje svojstva učini da nestane deseci upozorenja, to je razlog za daljnje istraživanje, a ne znak da je temeljni problem riješen.
Korak 8: Provjerite popravak u razvojnom i produkcijskom okruženju
Ilustracija generirana AI-em: Nakon promjene koda, provjerite čisto ponovno učitavanje, ispravnu interaktivnost i produkcijsku verziju umjesto oslanjanja samo na razvojni sloj. Ovo nije stvarni snimak zaslona preglednika, Reacta ili Next.js-a; koristite provjerene veze na kod i dokumentaciju u članku kao izvor istine.
Ponašanje u razvoju može se razlikovati od optimizirane produkcijske verzije. Nakon što greška nestane lokalno, izvršite provjeru u stilu produkcijske verzije za svoj okvir. Za tipičan Next.js projekt, to često znači izgradnju i pokretanje aplikacije s vašim uobičajenim naredbama upravitelja paketa, a zatim izvođenje svježih navigacija i ponovnih učitavanja.
Koristite ovaj popis provjere:
Provjera
Dobar znak
Ako ne uspije
Svježe ponovno učitavanje
Nema greške pri hidrataci u konzoli
Ponovno provjerite najraniju komponentu koja se razlikuje
Početno vizualno stanje
Nema neželjenog treperenja ili zamjene
Učinite početno stanje determinističkim
Interakcije
Gumbi, obrasci, izbornici i stanje rade normalno
Potvrdite da se komponenta i dalje hidratizira i da se rukovatelji događajima dodaju
Produkcijska verzija
Isti ispravan rezultat kao u razvoju
Istražite ponašanje podataka, CDN-a, CSS-a ili optimizacije samo u produkciji
Onemogućena proširenja
Rezultat je nepromijenjen
Identificirajte ponašanje proširenja koja mijenjaju DOM
Ako izravno posjedujete React SSR ulaznu točku umjesto korištenja okvira, hydrateRoot također podržava povratne pozive za greške poput onRecoverableError, što može pomoći u bilježenju u produkciji. Korisnici okvira općenito ne bi trebali zamjenjivati ulaznu točku za hidrataciju okvira samo kako bi dodali prilagođeno rukovanje.
Kada isprobati drugačiju strategiju prikaza
Ilustracija generirana AI-em: Promijenite strategiju kada komponenta temeljno ne može proizvesti smislen HTML s poslužitelja, ali držite granicu samo za klijenta što manjom koliko je praktično. Ovo nije stvarni snimak zaslona preglednika, Reacta ili Next.js-a; koristite provjerene veze na kod i dokumentaciju u članku kao izvor istine.
Ponekad najbolji popravak nije prisiljavanje komponente u SSR. Razmislite o drugačijoj strategiji prikaza kada:
Komponenta je izgrađena oko window, canvasa, WebGL-a, mjerenja preglednika ili drugog API-ja dostupanog samo u pregledniku.
Widget treće strane službeno ne podržava SSR.
Smisleni sadržaj komponente u potpunosti ovisi o stanju lokalnom za uređaj, poput localStorage.
Podaci u stvarnom vremenu mijenjaju se toliko brzo da usklađivanje sa snimkom s poslužitelja ima malu vrijednost.
U tim slučajevima, ciljana granica samo za klijenta može biti čistija. Ključna riječ je ciljana. Onemogućavanje SSR-a za cijelu stranicu kako bi se prilagodilo jednom grafikonu ili uređivaču može nepotrebno žrtvovati koristan sadržaj prikazan na poslužitelju, ponašanje pri učitavanju i druge prednosti.
Uobičajeni popravci koji izgledaju uspješno, ali nisu
Precica
Zašto je nepotpuna
Bolji kriterij
Dodajte 'use client' svugdje
Klijentske komponente i dalje se mogu predprikazati u Next.js-u
Premjestite logiku samo za preglednik nakon hidratacije ili je namjerno izolirajte
Omotajte logiku prikaza u typeof window !== 'undefined'
Grana sama može stvoriti različiti markup pri prvom prikazu
Zadržite prvi prikaz identičnim
Koristite suppressHydrationWarning široko
Skriva upozorenje umjesto usklađivanja stanja aplikacije
Koristite samo za očekivano, lokalno, neizbježno neslaganje
Onemogućite SSR za cijelu stranicu
Može ukloniti simptom uklanjanjem hidratacije za previše UI-a
Koristite najmanju praktičnu granicu samo za klijenta
Testirajte samo klijentsku navigaciju
Neslaganje se može pojaviti samo pri izravnom zahtjevu ili tvrdom ponovnom učitavanju
Testirajte svježa učitavanja stranica prikazanih na poslužitelju
Ograničenja ovih popravaka
Greška pri hidrataci govori vam da su se prikaz na poslužitelju i klijentu razišli; ne dokazuje zašto. Isti simptom može proizaći iz logike aplikacije, mutacije preglednika, biblioteke, CDN-a, neispravnog HTML-a ili promjenjivih podataka. Ne postoji jedan isječak koda koji sigurno popravlja sve te slučajeve.
Također, uklanjanje upozorenja pri hidrataci ne jamči ispravnost drugdje. Komponenta samo za klijenta i dalje može imati utrke podataka. Deterministički prvi prikaz i dalje može prikazati zastarjele podatke nakon hidratacije. Ispravan DOM i dalje može sadržavati probleme s pristupačnošću. Tretirajte hidrataciju kao jednu vrata kvalitete, a ne kao jedinu.
Novi browser API u Reactu 19.3 također ne znači da bi svaki okvir trebao odmah zamijeniti svoj uspostavljeni obrazac samo za preglednik. Integracija okvira i instalirane verzije su važne. Ako je vaš projekt na starijoj verziji Reacta ili Next.js-a, slijedite dokumentaciju za to izdanje umjesto da slijepo kopirate noviji API.
Pouzdan redoslijed odlučivanja
Locirajte najmanju komponentu koja se ne slaže.
Provjerite promjenjive vrijednosti poput datuma, nasumičnih brojeva, formatiranja lokalizacije i podataka dohvaćenih dvaput.
Uklonite API-je dostupne samo u pregledniku iz prvog prikaza kompatibilnog s poslužiteljem.
Osigurajte da poslužitelj i prvi prikaz na klijentu koriste istu snimku podataka.
Validirajte HTML strukturu.
Isključite proširenja, SSR konfiguraciju CSS-in-JS-a i prepisivanje CDN/Edge-a.
Koristite Effect, ciljno prikazivanje samo za klijenta ili React 19.3 use(browser()) samo kada sadržaj doista ovisi o pregledniku.
Rezervirajte suppressHydrationWarning za mala, namjerna neslaganja.
Provjerite svježim ponovnim učitavanjem i produkcijskom verzijom.
Trajni popravak nije "natjerati React da prestane prigovarati". To je činjenje ugovora o početnom prikazu eksplicitnim: poslužitelj i preglednik trebali bi se slagati oko prvog korisničkog sučelja, ili bi dio samo za preglednik trebao biti namjerno izoliran tako da se od Reacta ne traži da hidratizira markup koji nikada ne bi mogao odgovarati.