IlmHamroh
JavaScript Full-stack/23-qism. Next.js12/43-dars16 daqiqa
Mundarija (25)

Next.js provider'lari: Context, tema va 3-tomon kutubxonalar App Router'da

Qisqacha: React Context faqat client komponentda ishlaydi — Server Component'da createContext build xatosi beradi. Shuning uchun provider alohida "use client" faylga chiqariladi va root layout'da {children} ni o'raydi. Sahifalar baribir server bo'lib qoladi: provider ularni prop sifatida oladi (kompozitsiya naqshi). Bir nechta provider bo'lsa — bitta providers.tsx ga yig'iladi. Brauzerga bog'liq kutubxonalar uchun — "use client" o'rash fayli yoki client komponent ichida next/dynamic bilan ssr: false.

Bu darsda

  • Tema provider'ini yozasiz va root layout'ga qo'yasiz — sahifalar serverda qoladi.
  • providers.tsx naqshini va QueryClientProvider ni App Router'da xavfsiz ulashni bilasiz.
  • Server'da new QueryClient() ni modul darajasida yaratish nega xavfli ekanini tushuntirasiz.
  • window ga bog'liq kutubxonani next/dynamic va ssr: false bilan ulaysiz (va bu nega faqat client komponentda ishlashini ko'rasiz).
  • portfolio ga v1 dagi tema tanlovini qaytarasiz.

Oldin bilishingiz kerak: Server va Client kompozitsiyasi, Context I, useSyncExternalStore, Qorong'i rejim va temalash.

1. Nega bu kerak?

v1 portfolio'da footer'da tema tanlovi bor edi — Qorong'i rejim darsidagi uchta radio: «Tizim», «Yorug'», «Qorong'i». Tanlov localStorage da saqlanardi, <html data-tema> atributi CSS ranglarini almashtirardi. v2 ga uni qaytaramiz.

Tema — butun ilovaning holati. Footer'dagi tanlov uni o'zgartiradi, boshqa joylar (masalan kelajakdagi kod bloklari ranglari) uni o'qiydi. React'da bunday umumiy holat uchun Context bor: provider tepada qiymat beradi, pastdagi istalgan komponent use(Kontekst) bilan oladi.

Muammo: Context — client narsa. Holat brauzerda yashaydi, provider qayta chizilganda iste'molchilar yangilanadi. Server Component'da bularning hech biri yo'q. Biz sinadik — server sahifada createContext:

text
Error: You're importing a module that depends on `createContext` into a React Server Component module. This API is only available in Client Components. To fix, mark the file (or its parent) with the `"use client"` directive.

Server Components darsidagi useState xatosining egizagi. Unda root layout'ni "use client" qilsakmi? Unda hamma sahifa client bo'lib qoladi — marked, sirlar, async sahifalar — hammasi buziladi. Bu darsning javobi — provider'ni kichik client faylga chiqarish.

Hayotiy o'xshatish: binodagi elektr tarmog'i. Elektr (Context qiymati) hamma xonaga yetadi, lekin hisoblagich va avtomat (provider) bitta — kirishdagi kichik shkafda. Xonalar (sahifalar) o'z holicha qoladi, ular faqat rozetkadan foydalanadi.

2. Provider — client fayl, sahifalar — server

2.1 Kanondagi TemaProvider

tsx
"use client";

import { createContext, use, useCallback, useSyncExternalStore } from "react";

// Tema provider (N-12): Context faqat Client Component'da.
// Root layout uni import qiladi, lekin children (server
// sahifalar) serverda qoladi — provider ularni prop sifatida oladi.
export type Tema = "tizim" | "yorug" | "qorongi";
const KALIT = "tema";
const HODISA = "tema:ozgardi"; // v1 W-20 dagi hodisa nomi

function oqi(): Tema {
  try {
    const t = localStorage.getItem(KALIT);
    return t === "yorug" || t === "qorongi" ? t : "tizim";
  } catch {
    return "tizim"; // localStorage o'chirilgan (maxfiy rejim, sandbox)
  }
}

function obuna(xabarBer: () => void) {
  window.addEventListener(HODISA, xabarBer);
  window.addEventListener("storage", xabarBer); // boshqa tabda o'zgarsa
  return () => {
    window.removeEventListener(HODISA, xabarBer);
    window.removeEventListener("storage", xabarBer);
  };
}

const TemaKonteksti = createContext<{
  tema: Tema;
  temaniQoy: (t: Tema) => void;
} | null>(null);

export function TemaProvider({ children }: { children: React.ReactNode }) {
  // getServerSnapshot — serverda va hydration paytida "tizim";
  // keyin brauzer qiymati. Mismatch xatosi yo'q (N-13).
  const tema = useSyncExternalStore(obuna, oqi, () => "tizim" as const);

  const temaniQoy = useCallback((t: Tema) => {
    try {
      if (t === "tizim") localStorage.removeItem(KALIT);
      else localStorage.setItem(KALIT, t);
    } catch {
      // saqlab bo'lmasa ham shu sahifada ishlayveradi
    }
    if (t === "tizim") delete document.documentElement.dataset.tema;
    else document.documentElement.dataset.tema = t;
    window.dispatchEvent(new Event(HODISA));
  }, []);

  return <TemaKonteksti value={{ tema, temaniQoy }}>{children}</TemaKonteksti>;
}

export function useTema() {
  const qiymat = use(TemaKonteksti);
  if (!qiymat) throw new Error("useTema faqat <TemaProvider> ichida ishlaydi");
  return qiymat;
}

Kanon izohlari telefonga moslab bo'lindi; bir nechta kod qatori kanonda 70 belgidan uzun. Asosiy qismlar:

Qism Nima qiladi
"use client" Provider — client chegarasi fayli
oqi() localStorage dan tema; xato bo'lsa — "tizim"
obuna() O'z hodisamiz (tema:ozgardi) va boshqa tabdagi storage hodisasi
useSyncExternalStore(obuna, oqi, () => "tizim") Tashqi manbaga obuna; uchinchi argument — server qiymati
temaniQoy Saqlaydi, <html data-tema> ni qo'yadi, hodisa chiqaradi
<TemaKonteksti value> React 19: Context'ning o'zi provider (.Provider shart emas)
useTema() use() bilan o'qiydi; provider tashqarisida — aniq xato

Tema manbasi — Context emas, localStorage. Context faqat uni pastga tarqatadi. useSyncExternalStore darsidagi naqsh: brauzer saqlagan narsani React holatiga ulash. Uning uchinchi argumenti — server snapshot — serverda chizishda ishlatiladigan qiymat. Nega aynan "tizim" va bu nega muhim — keyingi darsda.

window.dispatchEvent(new Event(HODISA)) — Custom events darsidagi o'z hodisamiz. v1 da ham tema shu nom bilan e'lon qilingan edi — kanon nomni saqladi.

2.2 Root layout'da

tsx
<body>
  <a className="otish" href="#asosiy">
    Asosiy kontentga o'tish
  </a>
  <TemaProvider>
    <SaytSarlavhasi />
    {children}
    <SaytPastki />
  </TemaProvider>
</body>

Root layout — server. U TemaProvider ni import qiladi (client chegarasidan o'tish) va unga children beradi. SaytSarlavhasi, sahifalar ({children}), SaytPastki — hammasi server komponentlar, lekin ular provider'ning ichida turibdi. Bu — Kompozitsiya darsidagi naqshning o'zi: provider ularni import qilmaydi, faqat qabul qiladi.

Provider ichidagi client komponentlar (TemaTanlov) Context'ni o'qiy oladi. Server komponentlar esa o'qiy olmaydi va o'qishi shart emas: ular brauzerda qayta chizilmaydi.

flowchart TB
  L["RootLayout — server"] --> P["TemaProvider — client"]
  P --> H["SaytSarlavhasi — server"]
  P --> S["sahifalar — server"]
  P --> F["SaytPastki — server"]
  F --> T["TemaTanlov — client<br/>useTema()"]

SaytPastki server komponent, lekin u TemaTanlov ni chizadi — va TemaTanlov provider'ning qiymatini oladi. Context React daraxti bo'ylab tarqaladi, fayl importlari bo'ylab emas. Server komponent oraliqda tursa ham, client bolalari provider'ni ko'radi.

2.3 Natija oynasida: provider va server bolalar

Kanon provider'ining modeli. localStorage o'rniga xotiradagi oddiy "do'kon" — natija oynasida saqlash sahifa yangilanganda tozalanadi, natija har doim bir xil bo'lishi uchun. Page — "server" komponent o'rnida.

tsx
import {
  createContext,
  use,
  useSyncExternalStore,
  type ReactNode,
} from "react";

type Theme = "tizim" | "yorug" | "qorongi";

// localStorage o'rnida: qiymat + obunachilar
const store = {
  value: "tizim" as Theme,
  listeners: new Set<() => void>(),
  set(t: Theme) {
    store.value = t;
    store.listeners.forEach((l) => l());
  },
  subscribe(l: () => void) {
    store.listeners.add(l);
    return () => store.listeners.delete(l);
  },
};

const ThemeContext = createContext<Theme | null>(null);

function ThemeProvider({ children }: { children: ReactNode }) {
  const theme = useSyncExternalStore(
    store.subscribe,
    () => store.value,
    () => "tizim" as const,
  );
  return <ThemeContext value={theme}>{children}</ThemeContext>;
}

function ThemePicker() {
  const theme = use(ThemeContext);
  return (
    <p>
      Mavzu: {theme}{" "}
      <button onClick={() => store.set("qorongi")}>Qorong'i</button>
    </p>
  );
}

function Page() {
  console.log("Page chizildi");
  return <h1>Bosh sahifa</h1>;
}

export default function App() {
  return (
    <ThemeProvider>
      <Page />
      <ThemePicker />
    </ThemeProvider>
  );
}

Konsolda:

text
Page chizildi

Ekranda:

text
Bosh sahifa
Mavzu: qorongi Qorong'i

«Qorong'i» bosildi — provider yangi qiymat oldi, ThemePicker qayta chizildi. "Page chizildi" esa bir marta: Page elementi App da yaratilgan va provider'ga children bo'lib kelgan — provider qayta chizilganda u o'zgarmaydi (Kompozitsiya darsidagi qoida). Next.js'da Page server komponent — u brauzerda umuman chizilmaydi.

Tekshirib ko'ring: SaytSarlavhasi (server) ichida useTema() chaqirsak nima bo'ladi?

Javob

Xato. useTema ichida use(TemaKonteksti) — hook va Context, ular faqat client komponentda. Server komponentga tema kerak bo'lsa (masalan logoning varianti), u kichik client komponentga ajratiladi — barg qoidasi (Client Components). Ko'pincha esa CSS yetadi: [data-tema="qorongi"] .logo { … } — JS'siz.

3. providers.tsx — hamma provider bir joyda

3.1 Naqsh

Real loyihada provider'lar ko'payadi: tema, server ma'lumoti keshi (TanStack Query), tarjimalar, bildirishnomalar. Har birini root layout'ga alohida qo'yish layout'ni chalkashtiradi. Odatiy yechim — bitta client fayl:

tsx
// src/app/providers.tsx
"use client";

import {
  QueryClient,
  QueryClientProvider,
} from "@tanstack/react-query";
import { useState } from "react";
import { TemaProvider } from "@/komponentlar/TemaProvider";

type Props = { children: React.ReactNode };

export function Providers({ children }: Props) {
  const [queryClient] = useState(() => new QueryClient());
  return (
    <QueryClientProvider client={queryClient}>
      <TemaProvider>{children}</TemaProvider>
    </QueryClientProvider>
  );
}

Root layout'da esa bitta qator: <Providers>{children}</Providers>.

3.2 Tuzoq: QueryClient ni modul darajasida yaratish

useState(() => new QueryClient()) — bejiz emas. TanStack Query darsida SPA'da const queryClient = new QueryClient() ni fayl boshida yozgan edingiz — u yerda bu to'g'ri edi: brauzerda bitta foydalanuvchi.

Next.js'da client komponent serverda ham chiziladi (Client Components darsidagi topilma). Server esa — bitta jarayon, hamma foydalanuvchilar uchun. Modul darajasidagi new QueryClient() server xotirasida bir marta yaratiladi va hamma so'rovlar uchun umumiy bo'lib qoladi. Ali'ning so'rovida keshlangan ma'lumot Vali'ning sahifasiga chiqib qolishi mumkin. useState ichida yaratilsa — har so'rov (va har brauzer) o'z nusxasini oladi.

Qoida kengroq: server tomonda modul darajasidagi o'zgaruvchan holat — hamma foydalanuvchilarniki. Provider uchun holat — faqat komponent ichida.

3.3 Kanonga TanStack Query kirmadi

Kanon portfolio da providers.tsx va TanStack Query yo'q. Sabab oddiy: client'da server ma'lumoti olinmaydi. Loyihalar, blog, GitHub profili — hammasi Server Component'larda, to'g'ridan. 19-qism o'lchovi bo'yicha Query birinchi yuklashga ~10 KB gzip qo'shadi — foydasiz qo'shilardi. Kanonda bitta provider (tema), shuning uchun u root layout'da to'g'ridan turibdi. Query qachon kerakligi — TanStack Query bilan Next.js darsida.

4. 3-tomon kutubxonalar

4.1 "use client" siz kutubxona

Ko'p kutubxonalar Next.js'gacha yozilgan: ichida hook'lar bor, lekin fayllarida "use client" yo'q. Server sahifaga to'g'ridan qo'yilsa — depends on useState turidagi xato. Yechim Kompozitsiya darsida ko'rgan o'rash fayli:

tsx
// komponentlar/Karusel.tsx
"use client";

export { Carousel as Karusel } from "boshqa-kutubxona";

Provider'lar ham shunday: kutubxonaning ThemeProvider, IntlProvider kabi komponentlari o'z "use client" faylingiz orqali ulanadi — providers.tsx aynan shu vazifani bajaradi.

4.2 window ga import paytida tegadigan kutubxonalar

Ba'zi kutubxonalar (xarita, grafik, matn muharrirlari) import paytidayoq window yoki document ga murojaat qiladi. "use client" ham yordam bermaydi — client komponent serverda ham chiziladi, import serverda ham bajariladi, natija — window is not defined.

Yechim — next/dynamic bilan kechiktirilgan import va ssr: false: "bu komponentni serverda umuman chizma, faqat brauzerda yukla".

tsx
// komponentlar/XaritaOrol.tsx
"use client";

import dynamic from "next/dynamic";

const Xarita = dynamic(() => import("./Xarita"), {
  ssr: false,
  loading: () => <p>Xarita yuklanmoqda…</p>,
});

export function XaritaOrol() {
  return <Xarita />;
}

ssr: false ni server komponentda yozsak-chi? Biz sinadik:

text
Error: `ssr: false` is not allowed with `next/dynamic` in Server Components. Please move it into a Client Component.

Tarjimasi: "Server Component'larda next/dynamic bilan ssr: false mumkin emas. Uni Client Component'ga ko'chiring". Shuning uchun yuqoridagi misolda "use client" li XaritaOrol o'rami bor — server sahifa <XaritaOrol /> ni bemalol ishlatadi.

Narxi: ssr: false komponenti HTML'da yo'q — birinchi ochilishda loading matni ko'rinadi, keyin JS yuklanib, chiziladi. Qidiruv boti xaritani ko'rmaydi. Faqat haqiqatan brauzersiz ishlamaydigan narsalar uchun ishlating. next/dynamic — React'ning lazy iga Next.js qo'shgan qulay o'ram.

Tekshirib ko'ring: grafik kutubxonasi faqat useEffect ichida window ga tegadi. ssr: false kerakmi?

Javob

Yo'q. Effekt serverda bajarilmaydi — oddiy "use client" yetarli, komponent serverda bo'sh holatda chiziladi. ssr: false faqat import paytida yoki chizish paytida window ga tegadigan kutubxonalar uchun.

5. Provider'ni qayerga qo'yish?

Joy Qachon
Root layout Butun saytga kerak: tema, tarjimalar
Bo'lim layout'i Faqat bir qismga: admin paneli holati, savatcha
Komponent ichida Bitta vidjet: forma holati, karusel

Qoida: provider'ni iloji boricha pastga. Root layout'dagi provider ham sahifalarni client qilmaydi (kompozitsiya), lekin har provider o'zi JS va brauzerda ishlaydigan kod. Faqat admin panelda kerak bo'lgan provider butun ochiq saytga yuklanmasin.

Hujjat yana bir sabab keltiradi: provider qanchalik chuqur bo'lsa, Next.js sahifaning statik qismlarini shunchalik yaxshi optimallaydi.

5.1 Server komponentlarda Context o'rniga nima?

Savol tug'iladi: server komponentlar bir-biriga umumiy ma'lumotni qanday uzatadi? Masalan, joriy foydalanuvchi — layout'ga ham, sahifaga ham, chuqurdagi kartaga ham kerak. Props bilan pastga uzatish ("props drilling") — Context I darsidagi muammo.

Server tomonda javob boshqacha: har komponent kerakli ma'lumotni o'zi so'raydi — await joriyFoydalanuvchi(). Uch joyda chaqirilsa, uch marta bazaga borish kerakmi? Yo'q: React'ning cache() funksiyasi bitta so'rov davomida natijani eslab qoladi — birinchi chaqiruv bazaga boradi, qolganlari xotiradan oladi. Bu naqsh — React cache() va Data Access Layer darsida. Hozircha qoida: client daraxtda — Context, server daraxtda — keshlangan funksiya chaqiruvi.

6. Portfolio qadami: tema provider (1-qism)

Bu dars va keyingi dars holat 13 ni quradi. Commit hali qilmang.

Fayl Nima
komponentlar/TemaProvider.tsx Client: Context + useSyncExternalStore + useTema()
komponentlar/TemaTanlov.tsx Client: v1 dagi radio fieldset (C-87)
komponentlar/SaytPastki.tsx Footer'ga <TemaTanlov />
app/layout.tsx <TemaProvider> header, sahifalar va footer'ni o'raydi
app/globals.css :root[data-tema="qorongi"], [data-tema="yorug"], tizim afzalligi :root:not([data-tema])

CSS'dagi tartib v1 dagidek: atribut yo'q bo'lsa — prefers-color-scheme (tizim), bor bo'lsa — tanlangan mavzu. Birinchi bo'yashdan oldingi skript (TemaSkripti) va suppressHydrationWarning — keyingi darsda: ularsiz qorong'i tanlagan odam bir lahza oq sahifa ko'radi.

Kanon o'lchovi: JS 143.4 → 143.9 KB (+0.5 KB — provider va tanlov). TanStack Query qo'shilmadi.

7. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
… depends on createContext into a React Server Component Context server faylda Provider'ni "use client" faylga
Hamma sahifa client bo'lib qoldi Root layout "use client" Faqat provider client, layout server
useTema faqat <TemaProvider> ichida ishlaydi Komponent provider tashqarisida Provider'ni yuqoriroqqa
Foydalanuvchilar bir-birining ma'lumotini ko'radi Modul darajasidagi new QueryClient() useState(() => new QueryClient())
`ssr: false` is not allowed … in Server Components next/dynamic server faylda "use client" o'ramiga ko'chiring
window is not defined kutubxona importida Kutubxona import paytida brauzerga tegadi next/dynamic + ssr: false
Kutubxona komponenti hook xatosi beradi Kutubxonada "use client" yo'q O'z o'rash faylingiz

8. Mashqlar

Mashqlar kurs/mashqlar/23/12-providerlar/ da.

1-mashq (oson): to'g'ri joy

  • Butun saytdagi til (uz/en) provider'i —
  • Faqat /admin dagi yon panel holati —
  • Bitta formaning ichki holati —
  • new QueryClient() qayerda yaratiladi —
Yechim
  • root layout — hamma sahifaga kerak.
  • admin layout — app/admin/layout.tsx; ochiq sayt uni yuklamaydi.
  • komponent ichida — Context shart ham emas, useState yetadi.
  • useState — useState(() => new QueryClient()): har so'rov va brauzerga o'z nusxasi.

2-mashq (o'rta): provider'larni birlashtirish

Funksiya yozing: composeProviders(providers) — provider komponentlar massivini oladi va bitta Providers komponentini qaytaradi: birinchi element — eng tashqi. LangProvider ("uz") va ThemeProvider ("yorug") bilan sinang; ichkaridagi Status ikkala qiymatni ko'rsatsin. Ishora: reduceRight bilan ichkaridan tashqariga o'rang.

Yechim
tsx
import { createContext, use, type ReactNode } from "react";

type Wrapper = (p: { children: ReactNode }) => ReactNode;

function composeProviders(providers: Wrapper[]): Wrapper {
  return function Providers({ children }) {
    return providers.reduceRight<ReactNode>(
      (inner, Provider) => <Provider>{inner}</Provider>,
      children,
    );
  };
}

const LangContext = createContext("en");
const ThemeContext = createContext("tizim");

const LangProvider: Wrapper = ({ children }) => (
  <LangContext value="uz">{children}</LangContext>
);
const ThemeProvider: Wrapper = ({ children }) => (
  <ThemeContext value="yorug">{children}</ThemeContext>
);

const Providers = composeProviders([LangProvider, ThemeProvider]);

function Status() {
  return (
    <p>
      til: {use(LangContext)}, mavzu: {use(ThemeContext)}
    </p>
  );
}

export default function App() {
  return (
    <Providers>
      <Status />
    </Providers>
  );
}

Ekranda:

text
til: uz, mavzu: yorug

reduceRight oxirgi provider'dan boshlaydi: avval ThemeProvider children ni o'raydi, keyin LangProvider uni. Natija — <LangProvider><ThemeProvider>…. Provider'lar o'nta bo'lsa ham, root layout'da bitta <Providers> qoladi. Tartib muhim bo'lishi mumkin: bir provider ikkinchisining qiymatini ishlatsa, u ichkarida turishi kerak.

3-mashq (qiyin): provider tashqarisida — aniq xato

Til provider'i yozing: LangProvider va useLang(). useLang provider tashqarisida chaqirilsa — "useLang faqat <LangProvider> ichida ishlaydi" xatosini tashlasin (Context sukut qiymati — null). App da ikki joyda sinang: provider ichida (Til: uz) va tashqarida — xatoni error boundary ushlab, Xato: … deb ko'rsatsin.

Yechim
tsx
import { Component, createContext, use, type ReactNode } from "react";

const LangContext = createContext<string | null>(null);

function LangProvider({ children }: { children: ReactNode }) {
  return <LangContext value="uz">{children}</LangContext>;
}

function useLang(): string {
  const lang = use(LangContext);
  if (lang === null) {
    throw new Error("useLang faqat <LangProvider> ichida ishlaydi");
  }
  return lang;
}

class Boundary extends Component<
  { children: ReactNode },
  { message: string | null }
> {
  state = { message: null as string | null };
  static getDerivedStateFromError(error: Error) {
    return { message: error.message };
  }
  render() {
    if (this.state.message) return <p>Xato: {this.state.message}</p>;
    return this.props.children;
  }
}

function LangLabel() {
  return <p>Til: {useLang()}</p>;
}

export default function App() {
  return (
    <>
      <LangProvider>
        <LangLabel />
      </LangProvider>
      <Boundary>
        <LangLabel />
      </Boundary>
    </>
  );
}

Konsolda:

text
Error: useLang faqat <LangProvider> ichida ishlaydi
The above error occurred in the <LangLabel> component.
React will try to recreate this component tree from scratch using the error boundary you provided, Boundary.

Ekranda:

text
Til: uz
Xato: useLang faqat <LangProvider> ichida ishlaydi

Sukut qiymati null va aniq xato — kanondagi useTema ning naqshi. Sukut qiymati "uz" bo'lganida, provider'ni unutish jim o'tardi: komponent ishlayveradi, lekin tilni o'zgartirish unga yetmaydi — topish qiyin xato. Konsoldagi uch qator — React'ning ushlangan xato haqidagi dev yozuvi.

4-mashq: Portfolio qadami

O'z portfolio ingizga TemaProvider, TemaTanlov (footer'da) va CSS'dagi data-tema qoidalarini qo'shing. Tekshiring: next dev da «Qorong'i» ni tanlang — sahifa qorong'i bo'lsin, boshqa tabda ham (storage hodisasi). Keyin sahifani yangilang va birinchi lahzaga e'tibor bering — oq chaqnash ko'rinadimi? Javobini keyingi darsda tuzatamiz.

Yechim

Namuna — «Portfolio qadami» bo'limidagi jadval va kanon TemaProvider. Yangilaganda oq chaqnash ko'rinishi kutilgan: HTML serverda data-tema siz keladi, provider esa faqat JS yuklangandan keyin atributni qo'yadi. Root layout "use client" emasligini tekshiring — TemaProvider faqat o'rovchi. Commit hali qilmang.

9. Real ishda

  • Har App Router loyihada providers.tsx yoki shunga o'xshash fayl bor: Query, tema, tarjima, analitika, bildirishnomalar (toast).
  • next-themes — tema uchun tayyor kutubxona. Kanon uni olmadi: v1 dagi o'z tizimimiz (Qorong'i rejim) bor edi va u kichikroq. Kutubxona qachon to'g'ri tanlov — Stil va tema darsida.
  • Server'dagi umumiy holat — haqiqiy hodisalar bor: modul darajasidagi kesh tufayli bir foydalanuvchining ma'lumoti boshqasiga ko'ringan. Kod tekshiruvida "bu o'zgaruvchi serverda hamma uchun umumiy emasmi?" — muhim savol.
  • next/dynamic + ssr: false — xaritalar (Leaflet), matn muharrirlari, eski grafik kutubxonalari uchun kundalik vosita.

Xulosa

  • Context va provider — faqat client: provider "use client" faylda, root layout esa server bo'lib qoladi.
  • Provider children ni qabul qiladi — sahifalar va header/footer server komponent bo'lib qoladi; Context React daraxti bo'ylab tarqaladi.
  • Ko'p provider — bitta providers.tsx; QueryClient — useState ichida, modul darajasida emas.
  • Kutubxona "use client" siz — o'rash fayli; import paytida window — next/dynamic + ssr: false (faqat client komponentda).
  • Kanon: bitta TemaProvider (+0.5 KB), TanStack Query kerak bo'lmadi.

Keyingi dars: Hydration va hydration xatolari — oq chaqnashni yo'qotamiz va server bilan brauzer "kelishmasa" nima bo'lishini haqiqiy tajribalar bilan ko'ramiz.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Next.js provider'lari: Context, tema va 3-tomon kutubxonalar App Router'da — IlmHamroh