Mundarija (29)
- Bu darsda
- 1. Nega bu kerak?
- 2. Hydration qanday ishlaydi
- 2.1 Ikki chizish — bitta natija
- 2.2 Natija oynasida: mismatch'ni o'zingiz chiqaring
- 3. Mismatch sabablari
- 3.1 Ro'yxat
- 3.2 Noto'g'ri HTML — React oldindan ogohlantiradi
- 3.3 Brauzer kengaytmalari va suppressHydrationWarning
- 4. Kanon tajribalari: tema va hydration
- 4.1 To'rt variant
- 4.2 Jim xato: checked
- 4.3 Shovqinli xato: matn farqi va oq sahifa
- 4.4 To'g'ri yechim: getServerSnapshot
- 4.5 "Mounted" naqshi
- 5. Tema chaqnashi: birinchi bo'yashdan oldingi skript
- 5.1 Muammo qolmoqda
- 5.2 TemaSkripti
- 6. Biz topdik: new Date() — build xatosi
- 7. Portfolio qadami: chaqnashsiz tema va commit
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): mismatch bo'ladimi?
- 2-mashq (o'rta): mounted naqshi bilan tuzating
- 3-mashq (qiyin): useSyncExternalStore bilan
- 4-mashq: Portfolio qadami
- 10. Real ishda
- Xulosa
- Manbalar
Next.js hydration xatosi: sabablari, suppressHydrationWarning va tema chaqnashi
Qisqacha: Hydration (jonlantirish) — React serverdan kelgan tayyor HTML'ni oladi, client'da komponentlarni xuddi shu HTML'ni chiqaradigandek chizadi va hodisalarni ulaydi. Shart bitta: brauzerdagi birinchi chizish server HTML'i bilan aynan bir xil bo'lishi kerak. Farq bo'lsa — hydration mismatch: React xato beradi va daraxtni client'da noldan qayta yaratadi. Sabablari:
Date.now(),Math.random(),window/localStoragega qarab chizish, til va sana formati, noto'g'ri HTML (<p>ichida<div>), brauzer kengaytmalari. Davosi — birinchi chizishni server bilan bir xil qilish (getServerSnapshot,useEffect) va faqat aniq bir atribut uchunsuppressHydrationWarning.
Bu darsda
- Hydration nima qilishini va nega "bir xil birinchi chizish" shartligini tushuntirasiz.
- Mismatch'ni natija oynasida o'zingiz chiqarasiz va React uni qanday tiklashini ko'rasiz.
- Kanonning uch tajribasini o'qiysiz: jim
checked, matn farqi va oq bo'lib qolgan qorong'i sahifa. getServerSnapshot,useEffect("mounted") vasuppressHydrationWarningni qachon ishlatishni bilasiz.portfolioda tema chaqnashini birinchi bo'yashdan oldingi skript bilan yo'qotasiz.
Oldin bilishingiz kerak: Provider'lar, useSyncExternalStore, Client Components, SPA uchun SEO.
1. Nega bu kerak?
Provider'lar darsining oxirida bir muammo qoldi. «Qorong'i» ni tanlab, sahifani yangilang — bir lahzaga oq sahifa chaqnaydi, keyin qorong'i bo'ladi. Kechasi telefonda o'qiyotgan odamning ko'ziga — xuddi chiroq yoqilgandek.
Sabab: HTML serverda tayyorlanadi. Server foydalanuvchining localStorage ini ko'rmaydi — u brauzerda. Shuning uchun HTML "tizim" mavzusi bilan keladi, va faqat JS yuklanib, provider ishlagandan keyin data-tema="qorongi" qo'yiladi.
"Unda serverda emas, brauzerda to'g'ridan localStorage dan o'qib chizaylik" — birinchi xayolga keladigan yechim. Kanon aynan shuni sinab ko'rdi va yanada yomon natija oldi: qorong'i mavzu tanlangan, lekin sahifa oq bo'lib qoldi. Nega — hydration'ning qoidasida.
Hayotiy o'xshatish: binokor rasm bo'yicha uy quradi, keyin elektrik keladi va simlarni rasm bo'yicha tortadi. Rasm va uy bir xil bo'lsa — hammasi joyida. Elektrik devor rasmda boshqa joyda ekanini ko'rsa, simni "taxminan" tortmaydi — devorni buzib, o'z rasmi bo'yicha qayta quradi. Hydration'da elektrik — React, rasm — client'dagi birinchi chizish, uy — server HTML'i.
2. Hydration qanday ishlaydi
2.1 Ikki chizish — bitta natija
sequenceDiagram
participant S as Server
participant B as Brauzer
participant R as React
S->>B: HTML (tayyor matn)
Note over B: matn darhol ko'rinadi
B->>R: JS yuklandi
R->>R: komponentlarni chizadi (birinchi marta)
R->>B: HTML bilan solishtiradi, hodisalarni ulaydi
Note over B: tugmalar endi ishlaydiReact birinchi client chizishda DOM yaratmaydi — u mavjud HTML'ni "qabul qiladi" va har tugunni o'z daraxtidagi elementga bog'laydi. Shuning uchun natija bir xil bo'lishi shart: React "bu <p> da 'Mavzu: tizim' bo'lishi kerak edi, men 'qorongi' chizyapman" deb ko'rsa, ishonch yo'qoladi.
Mismatch bo'lganda React 19 nima qiladi? Eng yaqin Suspense chegarasigacha (yo'q bo'lsa — butun ildizgacha) daraxtni tashlab yuboradi va client'da noldan chizadi. Sahifa ishlayveradi, lekin: server HTML'ining foydasi yo'qoladi, ekran "sakraydi", va keyingi bo'limlarda ko'rasiz — ba'zan ma'lumot ham yo'qoladi.
2.2 Natija oynasida: mismatch'ni o'zingiz chiqaring
Natija oynasida server yo'q, lekin uni taqlid qilish mumkin: #root ga "serverdan kelgan" HTML'ni yozamiz va React'ga hydrateRoot bilan "buni jonlantir" deymiz. Komponent esa boshqa matn chizadi:
import { hydrateRoot } from "react-dom/client";
const root = document.getElementById("root")!;
root.innerHTML = "<p>Mavzu: tizim</p>"; // serverdan kelgan HTML
function Legend() {
return <p>Mavzu: qorongi</p>; // brauzerdagi birinchi chizish
}
hydrateRoot(root, <Legend />, {
onRecoverableError(error) {
console.log("tiklandi:", (error as Error).message.slice(0, 60));
},
});Konsolda:
tiklandi: Hydration failed because the server rendered text didn't matEkranda:
Mavzu: qorongionRecoverableError — React tiklagan xatolarni ushlaydigan hydrateRoot sozlamasi; xabarni 60 belgigacha qisqartirdik. To'liq matni: "Hydration failed because the server rendered text didn't match the client. As a result this tree will be regenerated on the client" — "Server chizgan matn client'nikiga mos kelmagani uchun hydration muvaffaqiyatsiz. Natijada bu daraxt client'da qayta yaratiladi". Ekranda — client varianti: server HTML'i tashlab yuborildi.
Next.js hydrateRoot ni o'zi chaqiradi — loyihada bu qatorni yozmaysiz. Lekin ichkarida aynan shu jarayon.
3. Mismatch sabablari
3.1 Ro'yxat
| Sabab | Misol | Nega farq |
|---|---|---|
| Vaqt | Date.now(), new Date().toLocaleTimeString() |
Server va brauzer chizishi orasida vaqt o'tdi |
| Tasodif | Math.random(), crypto.randomUUID() |
Har chaqiruvda boshqa |
| Brauzer tekshiruvi | typeof window !== "undefined" ? … : … |
Serverda bir shox, brauzerda boshqa |
| Saqlangan qiymat | localStorage.getItem("tema") chizishda |
Serverda yo'q |
| Til va format | toLocaleString(), Intl |
Server va brauzer tili/ICU farqi |
| Noto'g'ri HTML | <p> ichida <div>, <a> ichida <a> |
Brauzer HTML'ni "tuzatadi", daraxt o'zgaradi |
| Brauzer kengaytmasi | Grammarly, tarjimon <body> ga atribut qo'shadi |
HTML React'gacha o'zgargan |
React'ning to'liq xato matni ham shu ro'yxatni beradi (kanon dev tajribasidan):
Hydration failed because the server rendered text didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:
- A server/client branch `if (typeof window !== 'undefined')`.
- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
- Date formatting in a user's locale which doesn't match thKanon xom faylida matn shu joyda kesilgan (tajriba skripti xabarni qisqartirgan) — davomida shu ro'yxatning qolgani bor.
Til va sana — portfolio uchun alohida masala. 21-qismda topgandik: Chrome Intl o'zbek lotin sanasini Node'dan boshqacha chiqaradi. Server (Node) "2026-yil sentabr" deydi, Chrome — boshqa narsa: client komponentda Intl bilan sana chizilsa — mismatch. Kanon oy nomlarini sana.ts da qo'lda yozgani (Fayl-asosli routing darsida) — shu muammoning ham oldini oldi.
3.2 Noto'g'ri HTML — React oldindan ogohlantiradi
Noto'g'ri ichma-ichlikni React hydration'gacha ham ushlaydi — dev rejimda oddiy chizishda:
export default function App() {
return (
<p>
Narx: <div>35 000</div>
</p>
);
}Konsolda:
In HTML, <div> cannot be a descendant of <p>.
This will cause a hydration error.
<App>
> <p>
> <div>Ekranda:
Narx:
35 000"HTML'da <div> <p> ning ichida bo'la olmaydi. Bu hydration xatosiga olib keladi". Nega? Brauzer server HTML'ini o'qiganda <p> ni <div> dan oldin yopib qo'yadi — HTML qoidasi (HTML tuzilishi). DOM'da <p>Narx: </p><div>35 000</div><p></p> bo'lib qoladi, React esa ichma-ich daraxt kutadi. Davosi — to'g'ri teg: <span> yoki <p> o'rniga <div>.
3.3 Brauzer kengaytmalari va suppressHydrationWarning
Grammarly kabi kengaytmalar sahifa yuklanishi bilan <body> ga o'z atributlarini qo'shadi (data-gr-ext-installed). React keladi — server HTML'ida bunday atribut yo'q edi. Bu sizning xatongiz emas, lekin konsol qizil.
Buning uchun React'da suppressHydrationWarning bor — "shu elementning o'z atributlari va matnidagi farqni kechir". Muhim cheklovlar:
- Faqat bitta daraja: elementning o'zi uchun, bolalariga tarqalmaydi.
- Xatoni yashiradi, tuzatmaydi: React farqni "yamamaydi", server qiymati qoladi.
Ikkinchisini natija oynasida ko'ring — yuqoridagi tajriba, faqat <p> da suppressHydrationWarning:
import { hydrateRoot } from "react-dom/client";
const root = document.getElementById("root")!;
root.innerHTML = "<p>Mavzu: tizim</p>";
function Legend() {
return <p suppressHydrationWarning>Mavzu: qorongi</p>;
}
hydrateRoot(root, <Legend />);Ekranda:
Mavzu: tizimXato yo'q — lekin ekranda server matni qoldi, client "qorongi" ni ko'rsatmadi. suppressHydrationWarning — "bu farqni bilaman, tegma" degani. Shuning uchun u faqat ataylab farq qiladigan, React tegmasligi kerak bo'lgan joyga: <html> atributlari (kengaytmalar, tema skripti), vaqt belgisi (<time>).
Tekshirib ko'ring:
<body suppressHydrationWarning>yozildi.<body>ichidagi<main>da matn farqi bo'lsa, xato chiqadimi?
Javob
Ha. suppressHydrationWarning faqat bitta daraja — <body> ning o'z atributlari uchun. Ichkaridagi <main> ga ta'sir qilmaydi. Butun daraxt uchun "xatolarni o'chirish" tugmasi yo'q — va bu yaxshi.
4. Kanon tajribalari: tema va hydration
4.1 To'rt variant
Kanon localStorage.tema = "qorongi" bilan sahifani ochib, to'rt xil yechimni o'lchadi:
| Variant | Hydration | Natija |
|---|---|---|
Kanon: useSyncExternalStore(obuna, oqi, () => "tizim") + skript |
0 (prod va dev) | Qorong'i fon, radio «Qorong'i» |
useState(() => typeof window === "undefined" ? "tizim" : oqi()) |
0 — jim | Radio «Tizim» — noto'g'ri |
O'sha + matnda mavzu (<legend>Mavzu: …</legend>) |
prod #418, dev — to'liq xabar |
Daraxt qayta yaratildi: data-tema qorongi qoldi, fon esa yorug' |
Footer'da new Date().getFullYear() |
— | Build xatosi |
4.2 Jim xato: checked
Ikkinchi variant eng xavfli — u hech qanday xato bermaydi. useState ning boshlang'ich funksiyasi serverda "tizim", brauzerda "qorongi" qaytaradi. Radio tugmalarda checked farq qiladi. Lekin React hydration paytida checked (va value) atributlarini solishtirmaydi — ular foydalanuvchi o'zgartiradigan "jonli" qiymatlar. Natija: konsol toza, ekranda esa «Tizim» belgilangan, holbuki odam «Qorong'i» ni tanlagan.
Konsoldagi "0 xato" — "xato yo'q" degani emas. Bu yerda faqat foydalanuvchi ko'zi topadi.
4.3 Shovqinli xato: matn farqi va oq sahifa
Uchinchi variantda o'sha kodga mavzu nomi matnda qo'shildi: <legend>Mavzu: {tema}</legend>. Endi farq matnda — React uni tekshiradi. Kanon xom natijasi (prod):
tanlangan radio: tema-qorongi
hydration/xato xabarlari: 1
pageerror: Minified React error #418; visit https://react.dev/errors/418?args[]=text&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings.#418 — production'dagi qisqartirilgan hydration xatosi, args[]=text — "matn farqi". Dev'da xuddi shu tajriba yuqoridagi to'liq "Hydration failed because…" xabarini berdi, va qo'shimcha:
Encountered a script tag while rendering React component. Scripts inside React components are never executed when rendering on the client. Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).Ikkinchi xabar — oqibat: React daraxtni client'da qayta yaratayotib <head> dagi tema skriptiga duch keldi ("React komponentini chizishda <script> tegi uchradi; client'da chizilgan skriptlar bajarilmaydi").
Va eng muhimi — foydalanuvchi nima ko'rdi. Kanon o'lchagan fon rangi:
| Variant | Fon (lab rang) |
|---|---|
| Kanon (to'g'ri) | lab(8.62821 …) — deyarli qora |
| Matn farqi bilan | lab(97.9665 …) — deyarli oq |
Qorong'i mavzuni tanlagan odam — oq sahifa oldi. Qiziq tomoni: atribut joyida qoldi. Xom faylda data-tema: qorongi, radio ham «Qorong'i». Lekin hisoblangan fon — yorug'. Ya'ni React daraxtni qayta yaratganda sahifa ko'rinishi buzildi, atribut esa "to'g'ri" ko'rinib turibdi. Aniq ichki sababni xom o'lchov ko'rsatmaydi — muhimi oqibat. Mismatch — konsoldagi qizil yozuv emas, haqiqiy foydalanuvchi zarari.
4.4 To'g'ri yechim: getServerSnapshot
Kanon varianti — Provider'lar darsidagi useSyncExternalStore(obuna, oqi, () => "tizim"). Uchinchi argument — server snapshot: React uni serverda va brauzerdagi hydration chizishida ishlatadi. Ikkalasida ham "tizim" — bir xil, mismatch yo'q. Hydration tugashi bilan React oqi() ni chaqiradi, "qorongi" ni oladi va oddiy yangilanish sifatida qayta chizadi.
const tema = useSyncExternalStore(obuna, oqi, () => "tizim" as const);
// server: "tizim"
// hydration: "tizim" ← bir xil, xato yo'q
// keyin: "qorongi" ← oddiy yangilanishKanon tekshiruvi (prod va dev bir xil):
interactive paytida data-tema: qorongi | fon: lab(8.62821 -6.3644 2.52036)
tanlangan radio: tema-qorongi
hydration/xato xabarlari: 0
Yorug' bosildi → data-tema: yorug localStorage: yorug4.5 "Mounted" naqshi
useSyncExternalStore — tashqi manba (saqlash, brauzer API) uchun. Oddiyroq holatlarda (faqat brauzerda ma'lum qiymat, obunasiz) — mounted naqshi: birinchi chizishda server bilan bir xil narsa, useEffect dan keyin haqiqiysi.
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
return <p>{mounted ? new Date().toLocaleTimeString() : "…"}</p>;Effekt faqat brauzerda, hydration'dan keyin ishlaydi — Client Components darsidagi WidthBadge mashqi aynan shu naqsh edi. Narxi: bitta qo'shimcha chizish va bir lahza "…".
5. Tema chaqnashi: birinchi bo'yashdan oldingi skript
5.1 Muammo qolmoqda
getServerSnapshot xatoni yo'qotdi, lekin chaqnash qoldi: HTML data-tema siz keladi, CSS tizim mavzusini (kunduzi — yorug') chizadi, keyin JS yuklanib qorong'iga o'tadi. Bu React'dan oldin — brauzerning birinchi bo'yashida hal bo'lishi kerak.
5.2 TemaSkripti
Next.js hujjatining "preventing flash before hydration" qo'llanmasidagi yechim — <head> da kichik inline skript: u HTML o'qilayotganda, CSS chizilishidan oldin bajariladi.
// Birinchi bo'yashdan OLDIN data-tema qo'yiladi — qorong'i
// tanlagan odam oq sahifani "chaqnab" ko'rmaydi (hujjat:
// guides/preventing-flash-before-hydration). <html
// suppressHydrationWarning> shu atribut uchun.
const KOD = `try{var t=localStorage.getItem("tema");if(t==="yorug"||t==="qorongi")document.documentElement.dataset.tema=t}catch(e){}`;
export function TemaSkripti() {
return <script dangerouslySetInnerHTML={{ __html: KOD }} />;
}KOD qatori kanonda bitta uzun satr — u brauzerga aynan shunday boradi, bo'linmadi. U v1 dagi skript bilan bir xil ishni qiladi: saqlangan mavzuni o'qib, <html data-tema> ga yozadi. try/catch — localStorage o'chirilgan bo'lsa (maxfiy rejim), sahifa buzilmasin.
Root layout'da:
<html lang="uz" suppressHydrationWarning>
<head>
<TemaSkripti />
</head>
<body>…</body>
</html>Endi suppressHydrationWarning aynan o'z joyida. Skript <html> ga data-tema="qorongi" qo'ydi — server HTML'ida bu atribut yo'q edi. React hydration'da <html> ning atributlari farqini ko'radi. Biz bu farqni ataylab qildik — <html> ga (faqat unga, bitta daraja) "kechir" deymiz. Ichkaridagi hamma narsa — oddiy qat'iy tekshiruv ostida.
Bitta ochiq masala: inline skript va qat'iy CSP bir-biriga zid. Kanonning qarori ('unsafe-inline', sahifalar statik) va nonce muqobili — proxy.ts va next.config darslarida.
6. Biz topdik: new Date() — build xatosi
Footer'da © {new Date().getFullYear()} — eng oddiy kod. Kanon uni sinadi:
Error: Route "/aloqa": Next.js encountered the unstable value `new Date()` while prerendering.
This value can change between renders, so it must be either prerendered or computed later.
Ways to fix this:
- [dynamic] Render at request time by adding a dynamic data access (e.g. `await connection()`) before this call
- [cache] Prerender and cache the value with `"use cache"`
- [client] Render the value on the client with `"use client"`
- [measure] If the value is for telemetry, use a timing API such as `performance.now()`"Oldindan chizish paytida beqaror qiymat new Date() uchradi. U chizishdan chizishga o'zgarishi mumkin, shuning uchun yo oldindan chizilib keshlanishi, yo keyinroq hisoblanishi kerak". Next 16 + Cache Components hydration oilasidagi xatoni build vaqtida ushladi: statik sahifada new Date() build kunini abadiy "muzlatib" qo'yardi.
To'rt yo'l: [dynamic] — har so'rovda chizish (Rendering strategiyalari); [cache] — keshlash; [client] — brauzerda; [measure] — o'lchov uchun performance.now(). Kanon eng oddiyini tanladi: yil matnda yozildi (© 2026). Yiliga bir marta qo'lda o'zgartirish — har sahifani dinamik qilishdan arzon.
7. Portfolio qadami: chaqnashsiz tema va commit
Provider'lar darsidagi fayllarga qo'shiladi:
| Fayl | Nima |
|---|---|
komponentlar/TemaSkripti.tsx |
<head> dagi inline skript |
app/layout.tsx |
<html suppressHydrationWarning>, <head><TemaSkripti /></head> |
komponentlar/SaytPastki.tsx |
Yil — matnda (© 2026) |
Kanon o'lchovi (5 sahifa): hydration 0, axe 0; interactive paytida data-tema=qorongi, radio «Qorong'i»; «Yorug'» → data-tema=yorug, localStorage=yorug. JS 143.4 → 143.9 KB (+0.5 — provider bilan birga).
git add -A
git commitCommit (kanon): Tema: TemaProvider (useSyncExternalStore), birinchi bo'yashdan oldingi skript, radio tanlov footer'da.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
Hydration failed because the server rendered text didn't match… |
Birinchi chizishda brauzer qiymati | getServerSnapshot yoki useEffect |
Minified React error #418 (prod) |
Xuddi shu, qisqartirilgan | Dev'da ochib, to'liq xabarni o'qing |
| Radio/checkbox noto'g'ri, xato yo'q | checked farqi tekshirilmaydi |
Birinchi chizish — server qiymati |
In HTML, <div> cannot be a descendant of <p> |
Noto'g'ri ichma-ichlik | To'g'ri teg (<span>, <div>) |
<body> atributlari farqi |
Brauzer kengaytmasi | <html>/<body> da suppressHydrationWarning |
unstable value new Date() while prerendering |
Statik sahifada joriy vaqt | Matnda, connection(), "use cache" yoki client |
| Tema chaqnaydi | data-tema JS'dan keyin |
<head> da inline skript |
suppressHydrationWarning ishlamadi |
Bolalarga tarqalmaydi | Farq qiladigan elementning o'ziga |
9. Mashqlar
Mashqlar kurs/mashqlar/23/13-hydration/ da.
1-mashq (oson): mismatch bo'ladimi?
Client komponentning birinchi chizishida:
<p>{Math.random()}</p>—<p>{props.title}</p>(serverdan kelgan satr) —<p>{localStorage.getItem("ism")}</p>—useEffectichidasetNow(Date.now())—<p><ul><li>…</li></ul></p>—
Yechim
- ha — har chaqiruvda boshqa son.
- yo'q — prop server va brauzerda bir xil.
- ha — serverda
localStorageyo'q (aslida u yerda xato beradi), brauzerda bor. - yo'q — effekt hydration'dan keyin ishlaydi.
- ha —
<p>ichida<ul>bo'lmaydi: brauzer<p>ni yopadi, daraxt o'zgaradi.
2-mashq (o'rta): mounted naqshi bilan tuzating
«Mismatch'ni o'zingiz chiqaring» blokini oling: server HTML'i <p>Mavzu: tizim</p>, brauzer esa qorongi ni biladi. Legend ni shunday o'zgartiring: birinchi chizishda tizim (server bilan bir xil), useEffect dan keyin qorongi. onRecoverableError hech narsa yozmasligi, effekt esa konsolga effekt: qorongi yozishi kerak.
Yechim
import { useEffect, useState } from "react";
import { hydrateRoot } from "react-dom/client";
const root = document.getElementById("root")!;
// <!-- --> — React SSR'dagi matn bo'laklari chegarasi
root.innerHTML = "<p>Mavzu: <!-- -->tizim</p>";
const saved = "qorongi"; // brauzerda localStorage'dan o'qilgan
function Legend() {
const [theme, setTheme] = useState("tizim"); // server bilan bir xil
useEffect(() => {
setTheme(saved);
console.log("effekt:", saved);
}, []);
return <p>Mavzu: {theme}</p>;
}
hydrateRoot(root, <Legend />, {
onRecoverableError(error) {
console.log("tiklandi:", (error as Error).message);
},
});Konsolda:
effekt: qorongiEkranda:
Mavzu: qorongi"tiklandi" qatori yo'q — hydration toza o'tdi. E'tibor bering: "server HTML'i" endi Mavzu: <!-- -->tizim. JSX'dagi Mavzu: {theme} — ikki alohida matn bo'lagi, va React serverda ular orasiga <!-- --> izohini qo'yadi (Server Components darsidagi sir tajribasida ko'rgandik). Usiz React bitta matn tugunini ikkita kutadi — va bu ham mismatch bo'lardi. Biz buni sinab topdik: birinchi urinishda izohsiz yozganimizda onRecoverableError ishladi. Ekranda baribir qorongi: effekt hydration'dan keyin holatni o'zgartirdi. Haqiqiy loyihada saved effekt ichida localStorage dan o'qiladi — effekt serverda ishlamaydi, shuning uchun xavfsiz.
3-mashq (qiyin): useSyncExternalStore bilan
O'sha vazifani useSyncExternalStore bilan yeching: kichik do'kon (value: "qorongi", subscribe), getServerSnapshot — "tizim". Hydration xatosiz o'tsin va ekranda Mavzu: qorongi bo'lsin. Har chizishni konsolga yozing — nechta chizish bo'ladi?
Yechim
import { useSyncExternalStore } from "react";
import { hydrateRoot } from "react-dom/client";
const root = document.getElementById("root")!;
// <!-- --> — React SSR'dagi matn bo'laklari chegarasi
root.innerHTML = "<p>Mavzu: <!-- -->tizim</p>";
const store = {
value: "qorongi",
subscribe: () => () => {},
};
function Legend() {
const theme = useSyncExternalStore(
store.subscribe,
() => store.value,
() => "tizim",
);
console.log("chizildi:", theme);
return <p>Mavzu: {theme}</p>;
}
hydrateRoot(root, <Legend />, {
onRecoverableError(error) {
console.log("tiklandi:", (error as Error).message);
},
});Konsolda:
chizildi: tizim
chizildi: qorongiEkranda:
Mavzu: qorongiIkki chizish: birinchisi (hydration) — server snapshot "tizim", HTML bilan bir xil; ikkinchisi — React o'zi getSnapshot ni chaqirib, "qorongi" ni ko'rdi va qayta chizdi. Effekt ham, useState ham kerak bo'lmadi — kanondagi TemaProvider aynan shunday ishlaydi.
4-mashq: Portfolio qadami
TemaSkripti ni yozing, root layout'ga <head> ichida qo'ying, <html> ga suppressHydrationWarning. Footer'dagi yilni matnga aylantiring. Tekshiring: «Qorong'i» ni tanlang, DevTools'da Network → "Slow 4G" ni yoqib sahifani yangilang — oq chaqnash bo'lmasligi kerak. Konsolda hydration xatosi yo'qligini tekshiring. Keyin commit.
Yechim
Namuna — «Tema chaqnashi» bo'limidagi kod va «Portfolio qadami» jadvali. Chaqnash qolsa — skript <head> da emas yoki CSS'dagi selektor (:root[data-tema="qorongi"]) skript qo'ygan atributga mos emas. Hydration xatosi chiqsa — suppressHydrationWarning <html> da emas yoki provider birinchi chizishda localStorage ni o'qiyapti (getServerSnapshot ni tekshiring).
10. Real ishda
- Hydration xatolari — Next.js loyihalarida eng ko'p uchraydigan xatolar oilasidan. Ko'pincha sabab arzimas: sana formatlash,
Math.random()bilanid(React'da buning uchunuseIdbor). - Production'dagi
#418kabi raqamli xatolar — Sentry kabi xizmatlarda qisqartirilgan xatolar; ularni dev'da takrorlab, to'liq xabarni o'qish — kundalik ish. - Tema chaqnashi — "noto'g'ri mavzu chaqnashi" muammosi:
next-themeskutubxonasi ham ichida aynan shu inline skriptni ishlatadi. - Intervyu savoli: "Hydration mismatch nima va qanday oldini olasiz?" — sabablar ro'yxati,
getServerSnapshot/useEffectvasuppressHydrationWarningning cheklovi bilan javob bering.
Xulosa
- Hydration — server HTML'iga hodisalarni ulash; brauzerdagi birinchi chizish server HTML'i bilan aynan bir xil bo'lishi shart.
- Mismatch'da React daraxtni client'da qayta yaratadi: kanon tajribasida
data-temaqorong'i qoldi, lekin fon oq bo'ldi. checked/valuefarqi jim o'tadi — "0 xato" har doim "to'g'ri" degani emas.- Birinchi chizish — server qiymati:
useSyncExternalStoreninggetServerSnapshoti yokiuseEffect(mounted). suppressHydrationWarning— faqat bitta element, xatoni yashiradi, tuzatmaydi; o'rni —<html>atributlari.- Tema chaqnashi —
<head>dagi inline skript bilan birinchi bo'yashdan oldin hal qilinadi.
Keyingi dars: Rendering strategiyalari: statik, dinamik, streaming — ○, ◐ va ƒ belgilarini to'liq ochamiz va sahifa qachon dinamik bo'lib qolishini o'lchaymiz.
Manbalar
- React hujjati —
hydrateRoot, hydration mismatch,suppressHydrationWarning: https://react.dev/reference/react-dom/client/hydrateRoot (2026-10-21 da o'qildi) - Next.js hujjati — Preventing flash before hydration: https://nextjs.org/docs/app/guides/preventing-flash-before-hydration
- Next.js xato sahifasi — blocking-prerender-current-time: https://nextjs.org/docs/messages/blocking-prerender-current-time
- Kanon o'lchovlari:
portfoliov2, holat 13 (to'rt tema varianti,13-tema*.txt, hydration xatolari prod/dev,new Date()build xatosi). Natija oynasidagihydrateRootbloklari — React 19.3.0 ning haqiqiy xulqi.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!