IlmHamroh
JavaScript Full-stack/23-qism. Next.js13/43-dars17 daqiqa
Mundarija (29)

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/localStorage ga 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 uchun suppressHydrationWarning.

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") va suppressHydrationWarning ni qachon ishlatishni bilasiz.
  • portfolio da 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 ishlaydi

React 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:

tsx
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:

text
tiklandi: Hydration failed because the server rendered text didn't mat

Ekranda:

text
Mavzu: qorongi

onRecoverableError — 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):

text
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 th

Kanon 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:

tsx
export default function App() {
  return (
    <p>
      Narx: <div>35 000</div>
    </p>
  );
}

Konsolda:

text
In HTML, <div> cannot be a descendant of <p>.
This will cause a hydration error.
  <App>
>   <p>
>     <div>

Ekranda:

text
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:

tsx
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:

text
Mavzu: tizim

Xato 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):

text
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:

text
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.

tsx
const tema = useSyncExternalStore(obuna, oqi, () => "tizim" as const);
// server:    "tizim"
// hydration: "tizim"   ← bir xil, xato yo'q
// keyin:     "qorongi" ← oddiy yangilanish

Kanon tekshiruvi (prod va dev bir xil):

text
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: yorug

4.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.

tsx
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.

tsx
// 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:

tsx
<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:

text
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).

bash
git add -A
git commit

Commit (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> —
  • useEffect ichida setNow(Date.now()) —
  • <p><ul><li>…</li></ul></p> —
Yechim
  • ha — har chaqiruvda boshqa son.
  • yo'q — prop server va brauzerda bir xil.
  • ha — serverda localStorage yo'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
tsx
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:

text
effekt: qorongi

Ekranda:

text
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
tsx
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:

text
chizildi: tizim
chizildi: qorongi

Ekranda:

text
Mavzu: qorongi

Ikki 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() bilan id (React'da buning uchun useId bor).
  • Production'dagi #418 kabi 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-themes kutubxonasi ham ichida aynan shu inline skriptni ishlatadi.
  • Intervyu savoli: "Hydration mismatch nima va qanday oldini olasiz?" — sabablar ro'yxati, getServerSnapshot/useEffect va suppressHydrationWarning ning 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-tema qorong'i qoldi, lekin fon oq bo'ldi.
  • checked/value farqi jim o'tadi — "0 xato" har doim "to'g'ri" degani emas.
  • Birinchi chizish — server qiymati: useSyncExternalStore ning getServerSnapshot i yoki useEffect (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

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Next.js hydration xatosi: sabablari, suppressHydrationWarning va tema chaqnashi — IlmHamroh