Mundarija (27)
- Bu darsda
- 1. Nega bu kerak?
- 2. Props drilling — muammoni ko'ramiz
- 3. Context: uch qadam
- 3.1 Yaratish, berish, olish
- 3.2 Qiymat o'zgarsa
- 3.3 Pastdan o'zgartirish: qiymat va funksiya birga
- 3.4 TypeScript: kontekst turi
- 4. Default qiymat va eng yaqin Provider
- 4.1 Provider yo'q bo'lsa
- 4.2 Ichma-ich Provider'lar
- 5. use(Context) — React 19
- 6. Eski yozuvlar: .Provider va .Consumer
- 7. Qachon Context kerak emas
- 8. Vazifalar qadami: qator hodisalari — Context orqali (1-qism)
- 8.1 Drilling vazifalar da
- 8.2 Kontekst fayli
- 8.3 Komponentlar
- 8.4 Hozircha — commit'siz
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): valyuta konteksti
- 2-mashq (o'rta): drilling'ni olib tashlang
- 3-mashq (qiyin): filial narxlari
- 11. Real ishda
- Xulosa
- Manbalar
React Context I: createContext, use va props drilling'siz ma'lumot uzatish
Qisqacha: Ma'lumot ko'p qavat pastdagi komponentga kerak bo'lsa, uni har oraliq komponent orqali props bilan tashish — props drilling. Context buni hal qiladi:
const Lang = createContext("uz")yarating, daraxtning yuqorisida<Lang value="en">bilan bering, kerakli joydauseContext(Lang)yokiuse(Lang)bilan oling. Oraliq komponentlar bu qiymat haqida hech narsa bilmaydi. Provider bo'lmasa — default qiymat, bir nechta bo'lsa — eng yaqini. Context — global o'zgaruvchi emas: qiymat o'zgarsa, uni o'qiyotgan komponentlar qayta chiziladi.
Bu darsda
- Props drilling nima va u qachon muammoga aylanishini ko'rsata olasiz.
createContext,<Context value>vauseContext/usebilan qiymat uzatasiz.- Default qiymat va ichma-ich Provider'lar qanday ishlashini tushuntirasiz.
use(Context)ninguseContextdan farqini bilasiz.- Context o'rniga props yoki kompozitsiya yetarli bo'lgan holatlarni ajratasiz.
Oldin bilishingiz kerak: Props, children va kompozitsiya, State'ni ko'tarish, Hooklar qoidalari.
1. Nega bu kerak?
«Bahor» saytiga sayyohlar ham kiradi, shuning uchun menyu ikki tilda: o'zbekcha va inglizcha. Tanlangan til App da saqlanadi. Lekin uni ishlatadigan joy — eng pastdagi Price komponenti ("Narx" yoki "Price" deb yozadi). Oraliqda esa MenuPage, MenuList, DishCard bor.
Sardor lang ni props bilan tushirdi: App → MenuPage → MenuList → DishCard → Price. To'rt qavat. MenuPage, MenuList va DishCard tilni o'zi ishlatmaydi, faqat pastga uzatadi. Keyin valyuta ham qo'shildi ("so'm" / "UZS") — yana to'rt joyga yangi prop. Bu holat props drilling ("props'ni burg'ulab tushirish") deb ataladi.
Hayotiy o'xshatish: oshxonadagi radio. Oshpaz ofitsiantlarga xabarni og'izdan-og'izga uzatmaydi ("Aliga ayt, u Valiga aytsin…"). U radio orqali e'lon qiladi — eshitishi kerak bo'lgan har kim to'lqinga ulanib eshitadi, oradagilar esa xabarni tashib yurmaydi. Context — shunday to'lqin.
2. Props drilling — muammoni ko'ramiz
import { useState } from "react";
function Price({ lang, amount }) {
return <b>{lang === "uz" ? "Narx" : "Price"}: {amount}</b>;
}
function DishCard({ lang, dish }) {
return (
<li>
{dish.name} — <Price lang={lang} amount={dish.price} />
</li>
);
}
function MenuList({ lang, dishes }) {
return (
<ul>
{dishes.map((d) => (
<DishCard key={d.id} lang={lang} dish={d} />
))}
</ul>
);
}
function MenuPage({ lang }) {
const dishes = [
{ id: 1, name: "Osh", price: 35000 },
{ id: 2, name: "Manti", price: 30000 },
];
return <MenuList lang={lang} dishes={dishes} />;
}
function App() {
const [lang, setLang] = useState("uz");
return (
<div>
<button onClick={() => setLang("en")}>English</button>
<MenuPage lang={lang} />
</div>
);
}Ekranda:
English
Osh — Price: 35000
Manti — Price: 30000Ishlaydi. Lekin lang beshta joyda yozilgan, to'rtta komponent imzosida turibdi, ulardan uchtasi uni ishlatmaydi. Muammolar:
- O'zgartirish qimmat. Yangi umumiy qiymat (valyuta, tema, foydalanuvchi) — yana hamma oraliq komponentni tahrirlash.
- Oraliq komponentlar "ifloslanadi".
MenuListning vazifasi — ro'yxat chizish. Tilga uning aloqasi yo'q, lekin imzosidalangbor. - Qayta ishlatish qiyinlashadi.
DishCardni boshqa sahifaga olib borsangiz, u yerda hamlangni tashib kelish kerak.
flowchart TD
A["App: lang"] -->|lang| B["MenuPage"]
B -->|lang| C["MenuList"]
C -->|lang| D["DishCard"]
D -->|lang| E["Price — ishlatadi"]
A2["App: Lang value"] -.->|"Context to'lqini"| E2["Price — use(Lang)"]
A2 --> B2["MenuPage"] --> C2["MenuList"] --> D2["DishCard"] --> E2Chap tomonda — props drilling: har strelka bitta lang prop'i. O'ng tomonda — Context: oraliq komponentlar oddiy, qiymat punktir bo'ylab to'g'ridan-to'g'ri pastga yetadi.
Tekshirib ko'ring: Props drilling har doim yomonmi?
App→Header→Logo— ikki qavat.
Javob
Yo'q. Ikki-uch qavatli aniq props — eng tushunarli yo'l: kodni o'qigan odam ma'lumot qayerdan kelganini darhol ko'radi. react.dev ham avval props bilan boshlashni maslahat beradi. Muammo — chuqur va ko'p joyda takrorlanadigan uzatish.
3. Context: uch qadam
3.1 Yaratish, berish, olish
import { createContext, useContext, useState } from "react";
// 1) Yaratish — default qiymat bilan
const LangContext = createContext("uz");
function Price({ amount }) {
const lang = useContext(LangContext); // 3) Olish
return <b>{lang === "uz" ? "Narx" : "Price"}: {amount}</b>;
}
function DishCard({ dish }) {
return <li>{dish.name} — <Price amount={dish.price} /></li>;
}
function MenuList({ dishes }) {
return (
<ul>
{dishes.map((d) => <DishCard key={d.id} dish={d} />)}
</ul>
);
}
function MenuPage() {
const dishes = [
{ id: 1, name: "Osh", price: 35000 },
{ id: 2, name: "Manti", price: 30000 },
];
return <MenuList dishes={dishes} />;
}
function App() {
const [lang, setLang] = useState("uz");
return (
<LangContext value={lang}> {/* 2) Berish */}
<button onClick={() => setLang("en")}>English</button>
<MenuPage />
</LangContext>
);
}Ekranda:
English
Osh — Price: 35000
Manti — Price: 30000Natija bir xil, lekin MenuPage, MenuList, DishCard dan lang yo'qoldi. Uchta qadam:
createContext(default)— modul darajasida, komponentdan tashqarida. Natija — kontekst obyekti, uni eksport qilib boshqa fayllarda ishlatasiz.<LangContext value={…}>— Provider (ta'minlovchi). U o'z ichidagi butun daraxtga qiymat beradi. React 19 dan kontekstning o'zi Provider bo'la oladi.useContext(LangContext)— eng yaqin yuqoridagi Provider qiymatini qaytaradi.
3.2 Qiymat o'zgarsa
Provider qiymati — oddiy state (lang). «English» bosilganda App qayta chiziladi, Provider yangi qiymat beradi va uni o'qiyotgan Price lar ham yangilanadi.
| Qadam | lang (App state'i) |
useContext natijasi |
Ekranda |
|---|---|---|---|
| boshida | "uz" |
"uz" |
Narx: 35000 |
| «English» | "en" |
"en" |
Price: 35000 |
Bu — global o'zgaruvchidan asosiy farq. window.lang = "en" deb yozsangiz, React buni sezmaydi va hech narsa qayta chizilmaydi. Context esa React'ning o'z mexanizmi: qiymat o'zgarsa, iste'molchilar (consumer — qiymatni o'qiydigan komponentlar) qayta chiziladi. Buning narxi va chegaralari — Context II darsida.
3.3 Pastdan o'zgartirish: qiymat va funksiya birga
Til tugmasi ham chuqurda bo'lsa-chi? Masalan, sahifa pastidagi Footer ichida. setLang ni yana props bilan tushirish — o'sha drilling. Yechim: Provider'ga obyekt beriladi — qiymat va uni o'zgartiruvchi funksiya birga:
import { createContext, use, useState } from "react";
const LangContext = createContext({ lang: "uz", setLang: () => {} });
function LangSwitcher() {
const { lang, setLang } = use(LangContext);
const next = lang === "uz" ? "en" : "uz";
return (
<button onClick={() => setLang(next)}>
{next === "en" ? "English" : "O'zbekcha"}
</button>
);
}
function Footer() {
return <footer><LangSwitcher /></footer>;
}
function Greeting() {
const { lang } = use(LangContext);
return <h2>{lang === "uz" ? "Xush kelibsiz!" : "Welcome!"}</h2>;
}
function App() {
const [lang, setLang] = useState("uz");
return (
<LangContext value={{ lang, setLang }}>
<Greeting />
<Footer />
</LangContext>
);
}Ekranda:
Welcome!
O'zbekchaHolat hali ham App da — "yagona haqiqat manbai" (State'ni ko'tarish) saqlandi. Context faqat yetkazib berish yo'li: LangSwitcher setLang ni chaqiradi, App ning state'i o'zgaradi, Provider yangi obyekt beradi va ikkala iste'molchi qayta chiziladi.
| Qadam | App dagi lang |
Greeting |
LangSwitcher |
|---|---|---|---|
| boshida | "uz" |
Xush kelibsiz! | English |
| «English» (pastdan) | "en" |
Welcome! | O'zbekcha |
Default qiymatdagi setLang: () => {} — "hech narsa qilmaydigan" funksiya: Provider'siz chizilgan LangSwitcher yiqilmaydi, faqat ishlamaydi. Bu ma'lum bir xatoni yashirib qo'yadi — Provider'ni unutganingizni sezmaysiz. Keyingi darsda buning yaxshiroq yo'lini ko'ramiz.
Tekshirib ko'ring: Nega
setLangni Provider'ga bermasdan,LangSwitcherning o'zidauseStateyozib qo'ya qolmaymiz?
Javob
Unda LangSwitcher ning o'z lang i bo'lardi — App dagisidan alohida. Tugma bosilganda faqat u o'zgarardi, Greeting eski tilda qolardi. State ikki komponentga umumiy bo'lsa, u ularning umumiy otasida turadi; Context esa faqat bu state'ni pastga yetkazadi.
3.4 TypeScript: kontekst turi
TypeScript kontekst turini default qiymatdan oladi. Ruxsat etilgan qiymatlar aniq bo'lsa, turni o'zingiz yozing:
import { createContext } from "react";
type Lang = "uz" | "en";
const LangContext = createContext<Lang>("uz");
export default function App() {
return (
<LangContext value="ru">
<p>Menyu</p>
</LangContext>
);
}Xato:
TS2322: Type '"ru"' is not assignable to type 'Lang'.""ru" turi Lang ga mos emas." Provider'ga noto'g'ri qiymat berish kompilyatsiyada ushlandi. createContext<Lang> — generik (Generics): kontekst qiymatining turi burchakli qavsda.
4. Default qiymat va eng yaqin Provider
4.1 Provider yo'q bo'lsa
createContext ga berilgan qiymat — "zaxira": yuqorida hech qanday Provider bo'lmasa, useContext shuni qaytaradi.
import { createContext, useContext } from "react";
const ThemeContext = createContext("yorug'");
function Panel() {
const theme = useContext(ThemeContext);
return <p>Tema: {theme}</p>;
}
function App() {
return (
<div>
<Panel />
<ThemeContext value="qorong'i">
<Panel />
</ThemeContext>
</div>
);
}Ekranda:
Tema: yorug'
Tema: qorong'iBirinchi Panel Provider tashqarisida — default. Ikkinchisi ichida — Provider qiymati. Default qiymat Provider'ning "boshlang'ich qiymati" emas. U faqat Provider umuman yo'q bo'lganda ishlaydi. Provider bor, lekin value unutilgan bo'lsa — boshqa narsa:
import { createContext, useContext } from "react";
const ThemeContext = createContext("yorug'");
function Panel() {
return <p>Tema: {useContext(ThemeContext)}</p>;
}
function App() {
return (
<ThemeContext>
<Panel />
</ThemeContext>
);
}Konsolda:
The `value` prop is required for the `<Context.Provider>`. Did you misspell it or forget to pass it?Ekranda:
Tema:"Provider uchun value prop'i majburiy. Xato yozdingizmi yoki unutdingizmi?" Natija — undefined, default emas: Provider bor, demak uning qiymati (undefined) ishlatiladi. valeu kabi xato yozilganda ham xuddi shu ogohlantirish chiqadi.
4.2 Ichma-ich Provider'lar
Bir xil kontekstning bir nechta Provider'i bo'lishi mumkin. Har iste'molchi eng yaqin yuqoridagini oladi:
import { createContext, useContext } from "react";
const BranchContext = createContext("bosh ofis");
function Address() {
return <li>Filial: {useContext(BranchContext)}</li>;
}
function App() {
return (
<ul>
<Address />
<BranchContext value="Chilonzor">
<Address />
<BranchContext value="Yunusobod">
<Address />
</BranchContext>
<Address />
</BranchContext>
</ul>
);
}Ekranda:
Filial: bosh ofis
Filial: Chilonzor
Filial: Yunusobod
Filial: ChilonzorTo'rtinchi Address yana "Chilonzor" ni oldi — ichki Provider faqat o'z bolalariga ta'sir qiladi. Bu xuddi CSS'dagi meros (Meros): eng yaqin ota qiymati ustun. Amalda shunday ishlatiladi: sahifaning bir qismini boshqa til yoki tema bilan ko'rsatish, test'da komponentni soxta qiymat bilan o'rash.
Tekshirib ko'ring: Komponent o'zi chizgan Provider'ning qiymatini o'qiy oladimi? Masalan,
Appichida<Lang value="en">va shuAppning o'zidauseContext(Lang).
Javob
Yo'q — App dagi useContext(Lang) App dan yuqoridagi Provider'ni qidiradi. O'zi qaytargan <Lang value="en"> faqat bolalariga ta'sir qiladi. App uchun bu "en" emas, default yoki undan yuqoridagi qiymat.
5. use(Context) — React 19
React 19 da kontekstni o'qishning ikkinchi usuli paydo bo'ldi: use. Farqi — uni shart ichida, erta return dan keyin ham chaqirish mumkin. useContext da bunday qilib bo'lmaydi:
function Price({ show }) {
if (!show) return null;
const lang = useContext(Lang); // ❌ erta return'dan keyin
return <p>{lang}</p>;
}ESLint (eslint-plugin-react-hooks 7.1.1) buni darhol ushlaydi:
7:16 error React Hook "useContext" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return? react-hooks/rules-of-hooks"useContext shartli chaqirilyapti. Hooklar har renderda aynan bir xil tartibda chaqirilishi kerak. Erta return dan keyin chaqirib qo'ymadingizmi?" — Hooklar qoidalari. use esa oddiy hook emas, bu qoidadan ozod:
import { createContext, use, useState } from "react";
const LangContext = createContext("uz");
function Price({ show }) {
if (!show) return <p>Narx yashirin</p>;
const lang = use(LangContext); // ✅ shartdan keyin ham mumkin
return <p>{lang === "uz" ? "Narx" : "Price"}: 35000</p>;
}
function App() {
const [show, setShow] = useState(false);
return (
<LangContext value="en">
<Price show={show} />
<button onClick={() => setShow(true)}>Ko'rsatish</button>
</LangContext>
);
}Ekranda:
Price: 35000
Ko'rsatishuse kontekstdan tashqari Promise'ni ham o'qiy oladi — bu imkoniyatni use(): promise va context darsida (18-qism) ko'ramiz. Yangi kodda qaysi birini tanlash — did masalasi: useContext hali ham to'liq qo'llab-quvvatlanadi, use esa qulayroq. vazifalar kanonida use ishlatilgan.
6. Eski yozuvlar: .Provider va .Consumer
React 19 gacha Provider faqat .Provider bilan yozilardi. Eski kodda va kutubxonalarda buni ko'p uchratasiz — u hozir ham ishlaydi:
import { createContext } from "react";
const LangContext = createContext("uz");
function App() {
return (
<LangContext.Provider value="en">
<LangContext.Consumer>
{(lang) => <p>Til: {lang}</p>}
</LangContext.Consumer>
</LangContext.Provider>
);
}Ekranda:
Til: en.Consumer — hooklardan oldingi usul: bolasi funksiya bo'ladi, qiymat uning argumenti ("render props", HOC va render props). React 19 e'lonida (2024-12-05) aytilgan: <Context> endi Provider sifatida ishlaydi, .Provider esa kelajakda eskirgan deb belgilanadi. Yangi kodda <LangContext value> va use/useContext yozing.
7. Qachon Context kerak emas
react.dev Context'dan oldin ikki yo'lni sinashni maslahat beradi.
1. Props bilan boshlang. O'nta props ham bir necha qavatda — normal. Aniq props — ma'lumot oqimini ko'rsatadi.
2. Kompozitsiya — JSX'ni children qilib bering (children va kompozitsiya). Ko'p hollarda drilling sababi — oraliq komponent o'zi chizishi kerak bo'lmagan narsani chizyapti. Masalan, Layout ga user ni faqat Avatar ga uzatish uchun beryapsiz. Buning o'rniga Avatar ni tayyor holda bering:
function Avatar({ user }) {
return <b>{user.name}</b>;
}
function Layout({ header, children }) {
return (
<section>
<header>{header}</header>
<main>{children}</main>
</section>
);
}
function App() {
const user = { name: "Jasur aka" };
return (
<Layout header={<Avatar user={user} />}>
<p>Bugungi buyurtmalar: 12</p>
</Layout>
);
}Ekranda:
Jasur aka
Bugungi buyurtmalar: 12Layout user haqida hech narsa bilmaydi — u faqat joy ajratadi. user App dan Avatar ga to'g'ridan-to'g'ri ketdi, Context'siz.
| Vaziyat | Yechim |
|---|---|
| 1–3 qavat, bir nechta komponent | props |
| oraliq komponent faqat "joy" beradi | kompozitsiya: children, header={<…/>} |
| ko'p joyda kerak bo'ladigan "muhit" qiymati: til, tema, joriy foydalanuvchi, ruxsatlar | Context |
| tez-tez o'zgaradigan katta ma'lumot (ro'yxat, sichqoncha joylashuvi) | ehtiyot bo'ling — Context II |
8. Vazifalar qadami: qator hodisalari — Context orqali (1-qism)
8.1 Drilling vazifalar da
Hodisalar darsidan beri ro'yxat qatorining tugmalari otaga xabar beradi: onAlmashtir, onOchir, onTahrirla, onSaqla, onBekor va fokus uchun tugmaRef. Ular bitta QatorAmallari obyektida, va bu obyekt uch qavat pastga tushadi:
App — amallar={{ onAlmashtir, onOchir, … }}
└── VazifaRoyxati — amallar={amallar} (o'zi ishlatmaydi)
└── VazifaQatori — {...amallar} (o'zi ishlatmaydi)
├── OddiyQator — onAlmashtir, onOchir, onTahrirla, tugmaRef
└── TahrirQatori — onSaqla, onBekorVazifaRoyxati va VazifaQatori ning vazifasi — ro'yxatni va qator turini tanlash. Hodisalar ularga kerak emas. Bu — darslik misolidagi props drilling. Yangi branch: refactor/kontekst.
8.2 Kontekst fayli
src/kontekst/qator-amallari.ts:
// qator-amallari.ts — ro'yxat qatorlari hodisalari Context orqali
// (17/#41). #11–#39 da QatorAmallari obyekti props bilan uch
// qavat pastga tushardi: App → VazifaRoyxati → VazifaQatori →
// OddiyQator. O'rtadagi ikkitasiga u kerak emas edi (props
// drilling) — endi qator o'zi oladi
import { createContext, use } from "react";
import type { QatorAmallari } from "../turlar.ts";
export const QatorAmallariKonteksti =
createContext<QatorAmallari | null>(null);
export function useQatorAmallari(): QatorAmallari {
const amallar = use(QatorAmallariKonteksti);
if (amallar === null) {
throw new Error(
"useQatorAmallari() — <QatorAmallariKonteksti value> ichida",
);
}
return amallar;
}Izoh qatorlari telefonga sig'ishi uchun qayta bo'lingan. Ikki yangilik bor. Default qiymat — null: hodisalarning "zaxira" varianti ma'nosiz, Provider'siz qator ishlamasligi kerak. useQatorAmallari — kontekstni o'qib, null ni tekshiradigan kichik funksiya. Bu naqsh (custom hook + null tekshiruv) va uning foydasini keyingi darsda ochamiz.
8.3 Komponentlar
App.tsx — VazifaRoyxati endi Provider ichida, amallar prop'i yo'q:
<ul ref={royxatRef} id="royxat" aria-labelledby={sarlavhaId}>
- <VazifaRoyxati
- vazifalar={korinadigan}
- sorov={qidiruv}
- tahrirId={tahrirId}
- amallar={{
+ {/* Qator hodisalari — Context (17/#41): VazifaRoyxati va
+ VazifaQatori ularni endi tashib o'tmaydi */}
+ <QatorAmallariKonteksti
+ value={{
onAlmashtir: katakniAlmashtir,
…
tugmaRef,
}}
- />
+ >
+ <VazifaRoyxati
+ vazifalar={korinadigan}
+ sorov={qidiruv}
+ tahrirId={tahrirId}
+ />
+ </QatorAmallariKonteksti>
</ul>VazifaQatori.tsx — imzo qisqardi:
-export function VazifaQatori({
- vazifa,
- sorov,
- tahrirda,
- amallar,
-}: Props) {
- // {...amallar} — obyektdagi har bir funksiya alohida prop bo'lib
- // o'tadi; qator faqat o'ziga keraklisini oladi (17/#06: spread)
+export function VazifaQatori({ vazifa, sorov, tahrirda }: Props) {
+ // Hodisalar (onAlmashtir...) — props'da emas: qatorning o'zi
+ // kontekstdan oladi (17/#41)
if (tahrirda) {
- return <TahrirQatori vazifa={vazifa} {...amallar} />;
+ return <TahrirQatori vazifa={vazifa} />;
}
- return <OddiyQator vazifa={vazifa} sorov={sorov} {...amallar} />;
+ return <OddiyQator vazifa={vazifa} sorov={sorov} />;
}VazifaRoyxati.tsx dan ham amallar olib tashlandi. Hodisa kerak bo'lgan ikki komponent esa o'zi oladi — OddiyQator.tsx:
-export function OddiyQator({
- vazifa,
- sorov,
- onAlmashtir,
- onOchir,
- onTahrirla,
- tugmaRef,
-}: Props) {
+export function OddiyQator({ vazifa, sorov }: Props) {
+ // Hodisalar — kontekstdan (17/#41), props zanjirisiz
+ const { onAlmashtir, onOchir, onTahrirla, tugmaRef } =
+ useQatorAmallari();TahrirQatori.tsx da ham xuddi shunday: const { onSaqla, onBekor } = useQatorAmallari();. Props turlari soddalashdi: Pick<QatorAmallari, …> & {…} o'rniga oddiy { vazifa; sorov }.
8.4 Hozircha — commit'siz
Testlar ham o'zgaradi. VazifaRoyxati.test.tsx endi ro'yxatni Provider bilan o'raydi — xuddi App dagidek:
// Hodisalar — Context orqali (17/#41), App'dagidek
return render(
<QatorAmallariKonteksti value={amallar}>
<ul>
<VazifaRoyxati
vazifalar={vazifalar}
sorov={sorov}
tahrirId={tahrirId}
/>
</ul>
</QatorAmallariKonteksti>,
);Bu — ichma-ich Provider'ning amaliy foydasi: test komponentga soxta (vi.fn()) hodisalarni Context orqali beradi. Commit hali qilinmaydi: shu branch'da keyingi darsda tema ham Context'ga o'tadi va ikkalasi bitta commit bo'ladi.
9. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| har doim default qiymat | iste'molchi Provider ichida emas | Provider'ni daraxtda yuqoriroqqa qo'ying |
The \value` prop is required for the `<Context.Provider>`…` |
value unutilgan yoki xato yozilgan |
<Ctx value={…}> |
React Hook "useContext" is called conditionally… |
useContext erta return dan keyin |
tepaga ko'chiring yoki use |
window.x = … dan keyin ekran o'zgarmadi |
global o'zgaruvchi — React bilmaydi | Context + state |
| komponent o'zi bergan qiymatni o'qimaydi | useContext yuqoridagi Provider'ni qidiradi |
qiymatni o'zgaruvchidan to'g'ridan-to'g'ri oling |
ikki xil createContext (nusxa) |
kontekst har fayl/renderda qayta yaratilgan | modul darajasida bitta, eksport qiling |
Oxirgi qator haqida: createContext ni komponent ichida chaqirsangiz, har renderda yangi kontekst yaratiladi va Provider bilan iste'molchi "boshqa-boshqa radio to'lqinida" bo'lib qoladi.
10. Mashqlar
Mashqlar kurs/mashqlar/17/41-context/ da.
1-mashq (oson): valyuta konteksti
Bo'sh joylarni to'ldiring:
const CurrencyContext = [___:createContext]("so'm");
function Price({ amount }) {
const currency = [___:useContext](CurrencyContext);
return <b>{amount} {currency}</b>;
}
function App() {
return (
<CurrencyContext [___:value]="UZS">
<Price amount={35000} />
</CurrencyContext>
);
}Yechim
import { createContext, useContext } from "react";
const CurrencyContext = createContext("so'm");
function Price({ amount }) {
const currency = useContext(CurrencyContext);
return <b>{amount} {currency}</b>;
}
function App() {
return (
<p>
<CurrencyContext value="UZS">
<Price amount={35000} />
</CurrencyContext>{" "}
| <Price amount={28000} />
</p>
);
}Ekranda:
35000 UZS | 28000 so'mIkkinchi Price Provider tashqarisida — default "so'm".
2-mashq (o'rta): drilling'ni olib tashlang
Quyidagi kodda discount (chegirma foizi) uch qavat pastga tushyapti. TypeScript'da DiscountContext yarating va oraliq komponentlardan discount ni olib tashlang. Chegirmani App dagi tugma o'zgartiradi. Narx hisobi: price * (100 - discount) / 100.
import { useState } from "react";
type Dish = { id: number; name: string; price: number };
type PriceProps = { price: number; discount: number };
function Price({ price, discount }: PriceProps) {
return <b>{(price * (100 - discount)) / 100}</b>;
}
type RowProps = { dish: Dish; discount: number };
function DishRow({ dish, discount }: RowProps) {
return (
<li>
{dish.name}: <Price price={dish.price} discount={discount} />
</li>
);
}
type MenuProps = { dishes: Dish[]; discount: number };
function Menu({ dishes, discount }: MenuProps) {
return (
<ul>
{dishes.map((d) => (
<DishRow key={d.id} dish={d} discount={discount} />
))}
</ul>
);
}
export default function App() {
const [discount, setDiscount] = useState(0);
const dishes = [{ id: 1, name: "Lag'mon", price: 28000 }];
return (
<div>
<button onClick={() => setDiscount(10)}>Chegirma 10%</button>
<Menu dishes={dishes} discount={discount} />
</div>
);
}Ekranda:
Chegirma 10%
Lag'mon: 25200Yechim
import { createContext, use, useState } from "react";
type Dish = { id: number; name: string; price: number };
const DiscountContext = createContext(0);
function Price({ price }: { price: number }) {
const discount = use(DiscountContext);
return <b>{(price * (100 - discount)) / 100}</b>;
}
function DishRow({ dish }: { dish: Dish }) {
return <li>{dish.name}: <Price price={dish.price} /></li>;
}
function Menu({ dishes }: { dishes: Dish[] }) {
return (
<ul>
{dishes.map((d) => <DishRow key={d.id} dish={d} />)}
</ul>
);
}
export default function App() {
const [discount, setDiscount] = useState(0);
const dishes = [{ id: 1, name: "Lag'mon", price: 28000 }];
return (
<DiscountContext value={discount}>
<button onClick={() => setDiscount(10)}>Chegirma 10%</button>
<Menu dishes={dishes} />
</DiscountContext>
);
}Ekranda:
Chegirma 10%
Lag'mon: 25200createContext(0) — TypeScript turini default qiymatdan oladi: Context<number>. Menu va DishRow endi faqat o'z ishini qiladi.
3-mashq (qiyin): filial narxlari
Har filialda narxlar o'zgacha bo'lishi mumkin. PriceListContext yarating: qiymati — Record<string, number> (taom nomi → narx). Default — umumiy narxlar: osh 35 000, manti 30 000. Yunusobod filialida osh 37 000 (manti — umumiy). Sahifada ikki blok: «Chilonzor» (Provider'siz — umumiy narxlar) va «Yunusobod» (o'z Provider'i bilan). Yunusobod Provider'i umumiy ro'yxatni ustidan yozsin — faqat farq qiladigan narxni bering.
Ishora: Provider ichida yuqoridagi qiymatni o'qib, ustiga yozish mumkin: { ...use(PriceListContext), Osh: 37000 } — buni alohida komponentda qiling.
Yechim
import { createContext, use } from "react";
import type { ReactNode } from "react";
type PriceList = Record<string, number>;
const PriceListContext = createContext<PriceList>({
Osh: 35000,
Manti: 30000,
});
function PriceOverride({
prices,
children,
}: {
prices: PriceList;
children: ReactNode;
}) {
const parent = use(PriceListContext); // yuqoridagi ro'yxat
return (
<PriceListContext value={{ ...parent, ...prices }}>
{children}
</PriceListContext>
);
}
function Branch({ name }: { name: string }) {
const prices = use(PriceListContext);
return (
<li>
{name}: osh {prices.Osh}, manti {prices.Manti}
</li>
);
}
export default function App() {
return (
<ul>
<Branch name="Chilonzor" />
<PriceOverride prices={{ Osh: 37000 }}>
<Branch name="Yunusobod" />
</PriceOverride>
</ul>
);
}Ekranda:
Chilonzor: osh 35000, manti 30000
Yunusobod: osh 37000, manti 30000PriceOverride — o'zi ham iste'molchi (yuqoridagi qiymatni o'qiydi), o'zi ham Provider (pastga yangisini beradi). Ichma-ich Provider'lar shu tarzda "meros + ustidan yozish" ni beradi. Mavzular (theme) tizimlarida xuddi shu naqsh bilan sahifaning bir qismi boshqa rangda chiziladi.
11. Real ishda
- Tema, til, joriy foydalanuvchi, ruxsatlar — Context'ning klassik ishlatilishi. Kutubxonalar ham uni ishlatadi: router joriy manzilni, forma kutubxonasi forma holatini, UI kutubxonasi temani Context orqali beradi.
- Test'da komponentni kerakli Provider bilan o'rab, soxta qiymat berish — kundalik ish (
vazifalardagiVazifaRoyxati.test.tsxkabi). - Kod ko'rigida ikki xil izoh uchraydi: "bu props drilling — Context'ga chiqaring" va aksincha "bu qiymat faqat bitta joyda kerak — Context ortiqcha, props yetadi".
- Intervyu savollari: "Props drilling nima va uni qanday hal qilasiz?", "Default qiymat qachon ishlaydi?", "
usevauseContextfarqi?", "Context'ning muqobillari qanday?".
Xulosa
- Props drilling — qiymatni ishlatmaydigan oraliq komponentlar orqali tashish; chuqur bo'lsa, o'zgartirish qimmat.
- Context:
createContext(default)→<Ctx value>→useContext(Ctx)yokiuse(Ctx). - Provider yo'q — default; bir nechta — eng yaqini;
valueunutilsa —undefinedva ogohlantirish. - Provider qiymati state bo'lsa, o'zgarganda iste'molchilar qayta chiziladi — global o'zgaruvchidan farqi shu.
useshartdan keyin ham chaqiriladi;.Provider/.Consumer— eski yozuv.- Avval props va kompozitsiya; Context — ko'p joyga kerak "muhit" qiymatlari uchun.
Keyingi dars: Context II: reducer bilan birga, performance va chegaralar — Context + useReducer bilan kichik global holat yasaymiz, qayta chizish narxini o'lchaymiz va vazifalar dagi temani Context'ga o'tkazamiz.
Manbalar
- React: "Passing Data Deeply with Context" — react.dev/learn/passing-data-deeply-with-context
- React:
createContext,useContext,use— react.dev/reference/react - React 19 e'loni: "
<Context>as a provider" (2024-12-05) — react.dev/blog/2024/12/05/react-19
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!