13-bo‘lim
Kontekst - useContext
Props burg'ulash muammosi, createContext va Provider, React 19 dagi qisqa shakl, odatiy qiymat va kontekstni qachon ishlatmaslik.
Ushbu bo‘lim mundarijasi
Props ma'lumotni yuqoridan pastga uzatadi. Lekin ma'lumot besh qavat pastga tushishi kerak bo'lsa-chi?
Muammo: props burg'ulash #
import { renderToStaticMarkup } from "react-dom/server";
function Tugma({ mavzu }) {
return <button className={mavzu}>Bosish</button>;
}
function Panel({ mavzu }) {
return <div><Tugma mavzu={mavzu} /></div>;
}
function Yon({ mavzu }) {
return <aside><Panel mavzu={mavzu} /></aside>;
}
function Ilova() {
const mavzu = "qorongi";
return <Yon mavzu={mavzu} />;
}
console.log(renderToStaticMarkup(<Ilova />));
<aside><div><button class="qorongi">Bosish</button></div></aside>
Yon va Panel ga mavzu umuman kerak emas - ular uni
faqat pastga uzatib beradi.
Bu props burg'ulash (prop drilling) deb ataladi. Ikki qavatda u muammo emas, beshta qavatda esa kod shovqinga to'ladi.
Kontekst bilan #
import { createContext, useContext } from "react";
import { renderToStaticMarkup } from "react-dom/server";
const MavzuKonteksti = createContext("yorug");
function Tugma() {
const mavzu = useContext(MavzuKonteksti);
return <button className={mavzu}>Bosish</button>;
}
function Panel() {
return <div><Tugma /></div>;
}
function Yon() {
return <aside><Panel /></aside>;
}
function Ilova() {
return (
<MavzuKonteksti value="qorongi">
<Yon />
</MavzuKonteksti>
);
}
console.log(renderToStaticMarkup(<Ilova />));
console.log(renderToStaticMarkup(<Tugma />));
<aside><div><button class="qorongi">Bosish</button></div></aside>
<button class="yorug">Bosish</button>
Yon va Panel endi mavzu haqida hech narsa bilmaydi.
Ikkinchi qator muhim: Tugma kontekstdan tashqarida
ishlatilganda, createContext ga berilgan odatiy qiymat
("yorug") ishlatildi.
React 18 va undan oldin shunday yozilardi:
<MavzuKonteksti.Provider value="qorongi">
<Yon />
</MavzuKonteksti.Provider>
React 19 da kontekstning o'zini komponent sifatida ishlatish mumkin:
<MavzuKonteksti value="qorongi">
Eski shakl hali ishlaydi, lekin yangisi qisqaroq. Internetdagi
qo'llanmalarning ko'pchiligi hali .Provider bilan yozilgan.
O'zgaruvchan kontekst #
import { createContext, useContext, useState } from "react";
import { chiz, bos, matn } from "./dom-muhit.mjs";
const MavzuKonteksti = createContext(null);
function Almashtirgich() {
const { mavzu, almashtir } = useContext(MavzuKonteksti);
return (
<button onClick={almashtir}>
Hozir: {mavzu}
</button>
);
}
function Korinish() {
const { mavzu } = useContext(MavzuKonteksti);
return <p id="korinish">Ko'rinish: {mavzu}</p>;
}
function Ilova() {
const [mavzu, ozgartir] = useState("yorug");
const qiymat = {
mavzu,
almashtir: () =>
ozgartir((o) => (o === "yorug" ? "qorongi" : "yorug")),
};
return (
<MavzuKonteksti value={qiymat}>
<Almashtirgich />
<Korinish />
</MavzuKonteksti>
);
}
await chiz(<Ilova />);
console.log(matn("button"), "|", matn("#korinish"));
await bos("button");
console.log(matn("button"), "|", matn("#korinish"));
Hozir: yorug | Ko'rinish: yorug
Hozir: qorongi | Ko'rinish: qorongi
Kontekstga obyekt berildi: qiymat va uni o'zgartiradigan funksiya.
Ikkala komponent ham bir vaqtda yangilandi - ular bir manbadan o'qiyapti.
O'z ilgagingiz bilan o'rash #
import { createContext, useContext, useState } from "react";
const MavzuKonteksti = createContext(null);
export function MavzuTaminlovchi({ children, boshlangich = "yorug" }) {
const [mavzu, ozgartir] = useState(boshlangich);
const qiymat = {
mavzu,
almashtir: () =>
ozgartir((o) => (o === "yorug" ? "qorongi" : "yorug")),
};
return <MavzuKonteksti value={qiymat}>{children}</MavzuKonteksti>;
}
export function useMavzu() {
const qiymat = useContext(MavzuKonteksti);
if (qiymat === null) {
throw new Error("useMavzu faqat MavzuTaminlovchi ichida ishlaydi");
}
return qiymat;
}
import { MavzuTaminlovchi, useMavzu } from "./mavzu-konteksti.mjs";
import { chiz, bos, matn } from "./dom-muhit.mjs";
function Tugma() {
const { mavzu, almashtir } = useMavzu();
return <button onClick={almashtir}>{mavzu}</button>;
}
function Xato() {
try {
useMavzu();
return <p id="xato">ishladi</p>;
} catch (x) {
return <p id="xato">{x.message}</p>;
}
}
await chiz(
<MavzuTaminlovchi boshlangich="qorongi">
<Tugma />
</MavzuTaminlovchi>,
);
console.log(matn("button"));
await bos("button");
console.log(matn("button"));
await chiz(<Xato />);
console.log(matn("#xato"));
qorongi
yorug
useMavzu faqat MavzuTaminlovchi ichida ishlaydi
Bu standart naqsh: kontekstning o'zini eksport qilmasdan, ikkita narsani berish:
- Ta'minlovchi komponent;
- O'z ilgagingiz -
useMavzu.
useMavzu ichidagi throw bejiz emas.
Tekshiruvsiz, kontekstdan tashqarida chaqirilganda null
qaytardi va xato ancha keyin - qiymat.mavzu o'qilganda -
chiqardi:
Cannot read properties of null (reading 'mavzu')
Bu xabar muammoning sababini aytmaydi. Yuqoridagi shakl esa aniq aytadi: ta'minlovchi unutilgan.
Xatoni imkon qadar erta va tushunarli qilish - yaxshi kutubxona yozishning asosiy qoidalaridan biri.
Kontekst o'zgarganda nima bo'ladi #
import { createContext, useContext, useState } from "react";
import { chiz, bos } from "./dom-muhit.mjs";
const Kontekst = createContext(null);
const izlar = [];
function Oquvchi() {
const qiymat = useContext(Kontekst);
izlar.push(`Oquvchi chizildi: ${qiymat}`);
return <p>{qiymat}</p>;
}
function Begona() {
izlar.push("Begona chizildi");
return <span>begona</span>;
}
function Ilova() {
const [son, ozgartir] = useState(1);
return (
<Kontekst value={son}>
<button onClick={() => ozgartir(son + 1)}>Oshirish</button>
<Oquvchi />
<Begona />
</Kontekst>
);
}
await chiz(<Ilova />);
izlar.push("--- bosildi ---");
await bos("button");
console.log(izlar.join("\n"));
Oquvchi chizildi: 1
Begona chizildi
--- bosildi ---
Oquvchi chizildi: 2
Begona chizildi
Begona kontekstni o'qimaydi, lekin u ham qayta chizildi.
Ko'p odam kontekstni "qayta chizishni kamaytirish" uchun deb o'ylaydi. Aslida teskarisi.
Yuqorida Begona kontekstga umuman tegmaydi, lekin baribir
qayta chizildi - chunki uning otasi qayta chizildi. Kontekst
buni o'zgartirmaydi.
Kontekst faqat props uzatishni soddalashtiradi, chizishlarni emas.
Agar kontekst qiymati tez-tez o'zgarsa va daraxt katta bo'lsa, bu sezilarli sekinlik keltirishi mumkin. Yechimlar:
- Kontekstni bo'lish - o'zgarmaydigan qismini alohida kontekstga ajratish;
childrenorqali uzatish (16-bo'lim);memobilan qismlarni ajratish (17-bo'lim).
Qachon kontekst kerak emas #
| Holat | Yechim |
|---|---|
| Ikki qavat pastga uzatish | Oddiy props |
| Bitta komponentga tegishli holat | useState |
| Butun ilovaga kerak (mavzu, til, foydalanuvchi) | Kontekst |
| Murakkab, tez o'zgaradigan holat | Maxsus kutubxona |
Kontekst qulay ko'rinadi va uni haddan ortiq ishlatish oson.
Muammolari:
- Komponent qayerdan ma'lumot olayotgani ko'rinmaydi - props kabi ochiq emas.
- Komponentni alohida sinash qiyinlashadi: test uchun ham ta'minlovchi kerak bo'ladi.
- Qayta ishlatish qiyinlashadi: komponent endi ma'lum bir kontekstga bog'lanib qoladi.
Amaliy qoida: kontekst - butun ilovaga tegishli, kam o'zgaradigan narsalar uchun: mavzu, til, kirgan foydalanuvchi, marshrutlash.
Ikki-uch qavatli uzatish uchun oddiy props yaxshiroq: u ochiq va kuzatish oson.
- To'rt qavatli props burg'ulash yasang.
- Uni kontekst bilan almashtiring.
createContextga odatiy qiymat berib, ta'minlovchisiz sinang.- Kontekstga obyekt berib, funksiyani ham uzating.
- React 19 ning qisqa shaklini ishlating.
- Eski
.Providershaklini ham yozib ko'ring. - O'z ilgagingiz bilan kontekstni o'rang.
- Ta'minlovchisiz chaqirganda tushunarli xato bering.
- Kontekst o'zgarganda qaysi komponentlar chizilishini kuzating.
- Ikki qavatli uzatishni props bilan qoldiring.
Xulosa #
- Kontekst props burg'ulash muammosini hal qiladi.
createContext(odatiy)yaratadi,useContexto'qiydi.- React 19 da
<Kontekst value={...}>-.Providerkerak emas. - Odatiy qiymat faqat ta'minlovchisiz ishlatilganda amal qiladi.
- Standart naqsh: ta'minlovchi + o'z ilgagingiz, tekshiruv bilan.
- Kontekst unumdorlik vositasi emas - u qayta chizishni kamaytirmaydi.
- Kontekst kam o'zgaradigan, butun ilovaga tegishli narsalar uchun.
Keyingi bo'limda useReducer ni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.