12.1-bob: Context API (chuqur)
12-QISM — State Management va Data Fetching · 1-mavzu
1. Kirish va motivatsiya
11-QISM (React)da biz Context'ni bir necha marta — auth (11.5, 11.15), theme 11.5-bob, custom hook bilan 11.7-bob, TypeScript bilan 11.14-bob — ko'rib o'tdik. Endi 12-QISM (State Management)ning birinchi bobida unga chuqur kiramiz: Context aslida nima, ichida qanday ishlaydi, re-render xulqi (eng muhim va eng ko'p tuzoq beruvchi mavzu), uni to'g'ri optimallashtirish, va eng muhimi — qachon Context yetarli, qachon Redux/Zustand kerak. Bu — state management mavzusining poydevori: Context'ni chuqur tushunmasdan, Redux yoki Zustand'ni to'g'ri tanlab bo'lmaydi.
State management — bu kitobning eng ko'p "noto'g'ri tushunilgan" mavzularidan biri. Ko'p dasturchi "global state kerak bo'lsa Redux ishlat" deb o'ylaydi, lekin aslida ko'p holatda Context yetarli (yoki hatto kerak emas — ma'lumot serverdan bo'lsa, u TanStack Query'ning ishi — 12.4). Boshqalar Context'ni hamma narsaga ishlab, performance muammolariga duch keladi. Haqiqat — balansda: har vositaning o'z o'rni bor. Bu bobda Context'ning kuchli tomonlarini (oddiy, o'rnatilgan, hech narsa o'rnatish kerak emas) va cheklovlarini (re-render, selektor yo'q) aniq tushunamiz — toki keyingi boblarda (Redux, Zustand, Query) to'g'ri qaror qabul qila olasiz.
Bu bob: Context muammosi (props drilling — chuqur), Context arxitekturasi (createContext/Provider/useContext — ichki mexanizm), re-render xulqi (Context nega va qachon re-render keltiradi — eng muhim), value barqarorligi (memo — 11.6: 2.9), Context bo'lish (state + dispatch ajratish), Context + useReducer (mini-Redux), ko'p Context va provider kompozitsiyasi, performance tuzoqlari va yechimlari (selektor naqshi, use-context-selector), type-safe Context (11.14 davomi), qachon Context, qachon Redux/Zustand/Query (eng muhim qaror), va Server Components va Context (Next.js — 13). Mavzuni to'liq, performance va arxitektura fokusi bilan ochamiz.
O'xshatish: Context — bu binoning markaziy radio-eshittirish tizimi. Props drilling (Context'siz) — bu xabarni qo'ldan-qo'lga uzatish: direktor (yuqori komponent) xabarni o'rinbosariga, u bo'lim boshlig'iga, u xodimga... har qatlam orqali (zerikarli, biror joyda unutiladi). Context — bu markaziy karnay: direktor bir marta e'lon qiladi (Provider), va istalgan xonadagi istalgan xodim (consumer) uni to'g'ridan eshitadi (oraliq qatlamlar orqali emas). LEKIN — bu karnayning o'ziga xosligi bor: karnay bir narsani o'zgartirsa (value yangilansa), uni tinglab turgan barcha xona (consumer) e'tibor beradi (re-render) — hatto o'zgargan qism unga tegishli bo'lmasa ham. Shuning uchun bitta katta karnay (hamma narsani eshittiruvchi) o'rniga, bir necha alohida karnay (har biri o'z mavzusi — auth, theme, savat) ishlatish afzal — toki savat o'zgarganda faqat savatni tinglab turganlar e'tibor bersin (auth'ni tinglab turganlar emas).
Nega muhim?
- State management poydevori — Context'ni chuqur bilmasdan Redux/Zustand qachon kerakligini tushunmaysiz.
- Performance — Context re-render tuzog'i — eng keng frontend performance muammosi (11.11 davomi).
- O'rnatilgan, bepul — Context React'ning o'zida (kutubxona emas) — oddiy global state uchun ideal.
- To'g'ri qaror — "Redux kerakmi yoki Context yetadimi?" — senior darajadagi dasturchi har kuni javob beradigan savol.
2. Nazariya — chuqur tushuntirish
2.1. Props drilling muammosi (chuqur)
PROPS DRILLING — ma'lumotni faqat CHUQURDAGI komponentga yetkazish uchun
har ORALIQ qatlamdan qo'lda uzatish (zerikarli, mo'rt):
App (user)
│ props: user
▼
Layout (user) ──────── oraliq (user'ni ishlatmaydi, faqat uzatadi)
│ props: user
▼
Sidebar (user) ─────── oraliq (user'ni ishlatmaydi)
│ props: user
▼
UserMenu (user) ────── BU YERDA kerak (lekin 3 qatlam orqali keldi!)
MUAMMOLAR:
Oraliq komponentlar keraksiz props oladi (Layout/Sidebar user'ni bilmasin edi)
Yangi prop qo'shsa — HAR qatlamni o'zgartirish (mo'rt)
O'qish qiyin (prop qaydan keldi? — 5 fayl orqali)
Refactoring og'riqli (komponent ko'chsa — drilling buziladi)
Props drilling — 2-3 qatlamda maqbul; CHUQUR (5+) yoki KENG (ko'p komponent) — Context
Context — ma'lumotni MANBADAN to'g'ridan consumer'ga (oraliq qatlamlar o'tkaz emas)Props drilling muammosi — Context'ning asosiy sababi. Props drilling — ma'lumotni (masalan
user) faqat chuqurdagi bir komponentga yetkazish uchun har oraliq qatlamdan qo'lda uzatish. Misol:userApp'da, lekinUserMenu'ga kerak — uApp Layout Sidebar UserMenuzanjiri orqali uzatiladi, vaLayout/Sidebaruser'ni ishlatmaydi (faqat pastga uzatadi — "o'tkazuvchi"). Muammolar: (1) oraliq komponentlar keraksiz props oladi (Layoutuserhaqida bilishi shart emas edi); (2) yangi prop qo'shsangiz — har qatlamni o'zgartirish (mo'rt, ko'p fayl); (3) o'qish qiyin (prop qaydan keldi? — bir necha fayl orqali kuzatish); (4) refactoring og'riqli (komponent boshqa joyga ko'chsa, drilling zanjiri buziladi). Ikki nuqta: (1) props drilling 2-3 qatlamda maqbul (oddiy, aniq — ortiqcha murakkablik kerak emas); lekin chuqur (5+ qatlam) yoki keng (ko'p komponent bir ma'lumotni ulashadi) bo'lsa — Context; (2) Context ma'lumotni manbadan to'g'ridan consumer'ga uzatadi (oraliq qatlamlar "o'tkazuvchi" bo'lmaydi — ular ma'lumot haqida bilmaydi ham). Bu — Context'ning asosiy qiymati.
2.2. Context arxitekturasi — ichki mexanizm
3 QISM (11.5: 2.11 — chuqurroq):
1. createContext — kontekst "kanali" yaratiladi (default qiymat bilan):
const ThemeContext = createContext("light"); // default — Provider yo'q bo'lsa ishlatiladi
2. Provider — ma'lumot MANBASI (qiymatni pastga beradi):
<ThemeContext.Provider value={theme}>
{/* bu ichdagi BARCHA komponent theme'ni o'qiy oladi */}
</ThemeContext.Provider>
3. useContext — istalgan chuqurlikdan O'QISH (consumer):
const theme = useContext(ThemeContext); // eng yaqin Provider'ning value'sini oladi
ICHKI MEXANIZM (qanday ishlaydi):
- React har Context uchun ichki "qiymat egasi" (Provider) saqlaydi
- useContext(Ctx) — komponent daraxtida YUQORIGA qarab eng yaqin Provider'ni topadi
- Provider value o'zgarsa React shu Context'ni ishlatgan BARCHA consumer'ni re-render qiladi (2.3)
useContext eng YAQIN Provider'ni oladi (ichma-ich Provider — ichki g'olib)
Provider yo'q bo'lsa — createContext'dagi DEFAULT qiymat (yoki null — type-safe — 11.14)Context arxitekturasi — uch qism va ichki mexanizm (11.5: 2.11 chuqurroq). (1)
createContext(default)— kontekst "kanali"ni yaratadi (default qiymat bilan — Provider topilmasa shu ishlatiladi). (2)<Context.Provider value={...}>— ma'lumot manbasi: u value'ni o'z ichidagi butun daraxtga beradi. (3)useContext(Context)— istalgan chuqurlikdan o'qish (consumer): u eng yaqin Provider'ning value'sini oladi. Ichki mexanizm: React har Context uchun ichki holatda Provider qiymatini saqlaydi;useContext(Ctx)chaqirilganda, React komponentlar daraxtida yuqoriga qarab eng yaqinCtx.Providerni topadi va uning value'sini qaytaradi; va eng muhimi — Provider value o'zgarganda React o'sha Context'ni ishlatgan barcha consumer'ni re-render qiladi (2.3 — bu re-render xulqi). Ikki nuqta: (1)useContexteng yaqin Provider'ni oladi (ichma-ich Provider bo'lsa, ichki g'olib — bu nested theme/locale uchun foydali); (2) Provider yo'q bo'lsa —createContext'dagi default qiymat (yokinull— type-safe Context'da null tekshiruv bilan — 11.14: 2.13). Bu mexanizmni tushunish — Context'ning to'g'ri ishlatish va optimallashtirishning asosi.
2.3. Re-render xulqi — eng muhim tushuncha
ENG MUHIM (va eng ko'p tuzoq): Provider value O'ZGARganda — o'sha Context'ni
ishlatgan BARCHA consumer RE-RENDER bo'ladi (qism o'zgarmagan bo'lsa HAM):
<AppContext.Provider value={{ user, theme, cart }}>
<Profile /> user'ni ishlatadi (useContext(AppContext))
<Header /> theme'ni ishlatadi
<CartIcon /> cart'ni ishlatadi
</AppContext.Provider>
cart O'ZGARDI (faqat cart):
value obyekti yangi React: "value o'zgardi"
Profile, Header, CartIcon — UCHCHOVI ham RE-RENDER (user/theme tegmagan bo'lsa ham!)
Profile/Header bekorga render (cart ularga aloqasi yo'q)
IKKI SABAB consumer re-render bo'ladi:
1. Provider value o'zgardi (har consumer — yangi value oladi)
2. value REFERENTIAL o'zgardi (har render yangi obyekt — 11.6: 2.9 — eng keng tuzoq)
Context — SELEKTOR yo'q (value'ning bir QISMINI tinglab bo'lmaydi — hammasi yoki hech narsa)
Katta/tez o'zgaradigan value ko'p keraksiz re-render (Context cheklovi — 2.9, Redux/Zustand)Re-render xulqi — Context'ning eng muhim va eng ko'p tuzoq beruvchi tushuncha. Qoida: Provider'ning
value'si o'zgarganda, o'sha Context'ni ishlatgan barcha consumer re-render bo'ladi — value'ning faqat bir qismi o'zgarsa ham, va o'sha qism consumer'ga tegishli bo'lmasa ham. Misol:value={{ user, theme, cart }}— agar faqatcarto'zgarsa,Profile(user'ni ishlatadi),Header(theme),CartIcon(cart) — uchchovi re-render bo'ladi (Profile/Headerbekorga — cart ularga aloqasi yo'q). Ikki sabab consumer re-render bo'ladi: (1) Providervalue'si o'zgardi (har consumer yangi value oladi); (2) value referential o'zgardi — komponent ichida yaratilgan obyekt har render yangi havola (11.6: 2.9 — eng keng tuzoq — value har render yangidan yaralsa, consumer'lar har render re-render bo'ladi). Ikki kritik nuqta: (1) Context'da selektor yo'q — value'ning faqat bir qismini "tinglab" bo'lmaydi (hammasi yoki hech narsa —useContextbutun value'ni oladi); (2) shuning uchun katta yoki tez-tez o'zgaradigan value ko'p keraksiz re-render keltiradi (Context'ning asosiy cheklovi) — bu yerda Context bo'lish 2.6-bob yoki Redux/Zustand (selektorli — 2.9) kerak bo'ladi. Bu tushunchani anglash — Context'ni to'g'ri ishlatishning va keyingi state-management qaroplarining kalitidir.
2.4. Value barqarorligi — memo bilan
TUZOQ: Provider value har render YANGI obyekt consumer'lar HAR render re-render:
value har render yangi havola (11.6: 2.9):
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider value={{ user, setUser }}> {/* HAR render YANGI obyekt! */}
{children} {/* consumer'lar HAR render render */}
</AuthContext.Provider>
);
}
value'ni useMemo bilan barqarorlashtirish (11.6: 2.9):
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const value = useMemo(() => ({ user, setUser }), [user]); // user o'zgargandagina yangi
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
┌────────────────────────────────────────────────────────────┐
│ value={{ ... }}: har render yangi consumer'lar bekor render│
│ value=useMemo(...): user o'zgargandagina kerakli render │
└────────────────────────────────────────────────────────────┘
Provider value'ni DOIM useMemo bilan barqaror ushlash (har render yangi obyekt — tuzoq)
setUser (setState) barqaror — useMemo deps'da kerak emas (faqat user)Value barqarorligi — Context'ni to'g'ri ishlatishning majburiy qoidasi (11.6: 2.9 davomi). Tuzoq: agar Provider'ning
value'sini JSX'da to'g'ridan obyekt sifatida yozsangiz (value={{ user, setUser }}), u har render yangi havola oladi (11.6: 2.9 — referential equality) — natijada consumer'lar har render re-render bo'ladi (garchiusero'zgarmasa ham), chunki React value'ni===bilan solishtiradi va "o'zgardi" deb biladi. Yechim — value'niuseMemobilan barqaror ushlash:const value = useMemo(() => ({ user, setUser }), [user])— endi value faqatusero'zgargandagina yangi obyekt bo'ladi (aks holda oldingi havola qaytariladi consumer'lar bekorga render bo'lmaydi). Ikki nuqta: (1) Provider value'ni doimuseMemobilan barqaror ushlang (har render yangi obyekt — eng keng Context tuzog'i); (2)setUser(yokidispatch) — React barqaror kafolatlaydi (har render bir xil havola), shuning uchun uniuseMemodeps'ga qo'shish shart emas (faqat o'zgaradigan qiymatlar —user). Bu — har Context Provider'ning standart naqshi (value memo). Memoizatsiya anti-naqshi (nozik nuqta):useMemovalue re-render muammosini hal qilmaydi, balki uni kechiktiradi — value memo qilinsa ham,userhaqiqatan o'zgarganda barcha consumer baribir re-render bo'ladi (value memo faqat keraksiz — o'zgarmagan — renderlarni to'xtatadi). Shuning uchun value memo — zarur, lekin yetarli emas optimizatsiya; agarusertez-tez o'zgarsa va consumer'lar ko'p bo'lsa, memo yordam bermaydi — bu yerda Context'ni bo'lish 2.6-bob yoki selektor 2.9-bob kerak. Yana bir anti-naqsh: value obyektining har maydonini alohidauseMemoqilib, keyin ularni yana obyektga yig'ish — bu ortiqcha murakkablik (bittauseMemo(() => ({...}), [deps])yetadi). Xulosa: value memo — Context'ning poydevor qoidasi, lekin performance'ni faqat u orqali "tuzatib" bo'lmaydi (arxitektura — bo'lish/selektor — muhimroq).
2.5. Context + custom hook — toza interfeys
Context'ni TO'G'RIDAN ishlatish o'rniga — custom hook bilan o'rash (11.7, toza):
// Har komponentda: useContext(AuthContext) + null tekshiruv (takror)
// Custom hook — bir marta o'rab, qulay interfeys + xato himoyasi:
const AuthContext = createContext(null);
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const login = useCallback((u) => setUser(u), []);
const logout = useCallback(() => setUser(null), []);
const value = useMemo(() => ({ user, login, logout }), [user, login, logout]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
export function useAuth() { // custom hook (qulay + xavfsiz)
const ctx = useContext(AuthContext);
if (!ctx) throw new Error("useAuth AuthProvider ichida ishlatilishi kerak"); // himoya
return ctx;
}
// Ishlatish — toza:
const { user, login, logout } = useAuth(); // useContext emas (qulay, type-safe)
Custom hook — Context'ni o'rab, qulay (useAuth), xavfsiz (null xato), type-safe (11.14)
Context'ni TO'G'RIDAN export QILMASLIK — custom hook orqali (interfeys nazorati)Context + custom hook — Context'ni to'g'ri tashkil qilishning standart naqshi (11.7 bilan). Context'ni to'g'ridan (
useContext(AuthContext)) ishlatish o'rniga, uni custom hook bilan o'raysiz. Sabablar: (1) har komponentdauseContext+ null tekshiruvni takrorlamaslik; (2) qulay nom (useAuth()—useContext(AuthContext)dan toza); (3) xato himoyasi (Provider ichida ishlatilmasa — aniq xato xabari, undefined'dan yaxshiroq); (4) type-safe (11.14: 2.13). Naqsh:AuthProvider(value'ni memo bilan — 2.4),useAuthhook (useContext+if (!ctx) throw). Ishlatishda —const { user, login, logout } = useAuth()(toza, qulay). Ikki nuqta: (1) custom hook Context'ni o'rab, qulay/xavfsiz/type-safe interfeys beradi (har real loyiha shunday qiladi); (2) Context obyektini (AuthContext)ni to'g'ridan export qilmang — faqatuseAuthhook vaAuthProviderni export qiling (interfeys nazorati — foydalanuvchi Context bilan to'g'ridan ishlamasin, hook orqali). Bu — toza, qayta ishlatiladigan Context arxitekturasining poydevori.
2.6. Context bo'lish — state va dispatch ajratish
PERFORMANCE NAQSHI: Context'ni bo'lish (re-render kamaytirish — 2.3):
MUAMMO: bitta Context'da ham STATE, ham UPDATER — state o'zgarganda
faqat updater'ni ishlatgan komponent ham re-render (keraksiz):
YECHIM 1 — STATE va DISPATCH'ni alohida Context'ga ajratish:
const StateContext = createContext(null); // o'qish (tez-tez o'zgaradi)
const DispatchContext = createContext(null); // yozish (HECH o'zgarmaydi — barqaror)
function Provider({ children }) {
const [state, dispatch] = useReducer(reducer, initial);
return (
<DispatchContext.Provider value={dispatch}> {/* dispatch barqaror — re-render yo'q */}
<StateContext.Provider value={state}>
{children}
</StateContext.Provider>
</DispatchContext.Provider>
);
}
// faqat dispatch'ni ishlatgan komponent (tugma) state o'zgarganda RE-RENDER BO'LMAYDI
YECHIM 2 — mavzu bo'yicha bo'lish (auth/theme/cart alohida — 11.11: 2.9):
<AuthContext><ThemeContext><CartContext>... // cart o'zgarsa — auth/theme consumer tegmaydi
State + dispatch ajratish — faqat dispatch'ni ishlatgan komponent state'ga reaksiya qilmaydi
Mavzu bo'yicha bo'lish — bir mavzu o'zgarsa boshqasining consumer'lari tegmaydiContext bo'lish — Context performance optimizatsiyasining eng kuchli naqshi (2.3 re-render muammosini hal qiladi). Naqsh 1 — state va dispatch ajratish: bitta Context'da ham state (o'qish), ham updater (
dispatch/setState— yozish) bo'lsa, state o'zgarganda faqat dispatch'ni ishlatgan komponent (masalan "qo'shish" tugmasi — u state'ni o'qimaydi, faqat o'zgartiradi) ham re-render bo'ladi (keraksiz). Yechim — state'ni va dispatch'ni alohida Context'larga ajratish:StateContext(tez-tez o'zgaradi) vaDispatchContext(dispatch—useReducer/useStatesetter'i hech o'zgarmaydi, barqaror). Endi faqatdispatchni ishlatgan komponent state o'zgarganda re-render bo'lmaydi (chunki uStateContextni tinglamaydi). Naqsh 2 — mavzu bo'yicha bo'lish (11.11: 2.9): auth/theme/cart'ni alohida Context'larga ajratish (cart o'zgarsa — auth/theme consumer'lari tegmaydi). Ikki nuqta: (1) state + dispatch ajratish — faqat yozuvchi komponentlar (tugma, forma) state o'zgarishiga reaksiya qilmaydi (re-render tejash); (2) mavzu bo'yicha bo'lish — mustaqil ma'lumotlarni ajratish. Ikkala naqsh Context'ning re-render cheklovini (selektor yo'q — 2.3) qisman aylanib o'tadi (lekin to'liq emas — katta state uchun baribir Redux/Zustand afzal — 2.9).
2.7. Context + useReducer — mini-Redux
CONTEXT + useReducer — kichik global state (Redux'siz — 11.6 davomi):
// reducer (sof — 11.6: 2.3):
function cartReducer(state, action) {
switch (action.type) {
case "add": return [...state, action.payload];
case "remove": return state.filter(i => i.id !== action.payload);
case "clear": return [];
default: return state;
}
}
// Provider (useReducer + Context — state/dispatch ajratilgan — 2.6):
function CartProvider({ children }) {
const [cart, dispatch] = useReducer(cartReducer, []);
return (
<CartDispatchContext.Provider value={dispatch}>
<CartStateContext.Provider value={cart}>{children}</CartStateContext.Provider>
</CartDispatchContext.Provider>
);
}
// Hooklar:
const cart = useCartState(); // o'qish
const dispatch = useCartDispatch(); // yozish
dispatch({ type: "add", payload: product });
┌────────────────────────────────────────────────────────────┐
│ Context + useReducer = "mini-Redux" (markaziy reducer + │
│ dispatch + Context ulashish) — kichik ilova uchun yetadi │
└────────────────────────────────────────────────────────────┘
Context + useReducer — Redux'ning kichik modeli (kichik/o'rta ilova — Redux'siz)
Redux DevTools, middleware, selektor YO'Q — katta bo'lsa Redux/Zustand (2.9)Context + useReducer — kichik global state uchun "mini-Redux" (11.6 davomi).
useReducer(markaziy state mantig'i — 11.6) va Context (ulashish) ni birlashtirib, Redux'siz global state quriladi. Tuzilishi: (1) reducer (sof funksiya —(state, action) => newState— 11.6: 2.3); (2) Provider —useReducerbilan state/dispatch oladi va ularni Context'larga beradi (state va dispatch ajratilgan — 2.6 — performance); (3) hooklar —useCartState()(o'qish),useCartDispatch()(yozish). Ishlatishda komponentlardispatch({ type: "add", payload })bilan o'zgartiradi. Bu — Redux'ning kichik modeli (markaziy reducer + dispatch + Context orqali ulashish). Ikki nuqta: (1) Context + useReducer — kichik/o'rta ilova uchun yetadi (Redux o'rnatish kerak emas — React'ning o'zida); (2) lekin Redux DevTools (vaqt sayohati — kuzatish), middleware (async, logging), selektor (qism tinglash — 2.3) — bularning hech biri yo'q; ilova o'ssa va bu imkoniyatlar kerak bo'lsa — Redux Toolkit 12.2-bob yoki Zustand 12.5-bob. Bu naqsh — Context'ning state management'dagi eng kuchli ishlatilishi (oddiy global state).
2.8. Provider kompozitsiyasi — provider hell
MUAMMO: ko'p Provider — ICHMA-ICH "piramida" (provider hell):
<AuthProvider>
<ThemeProvider>
<CartProvider>
<ToastProvider>
<App /> // 4 qatlam ichma-ich (chalkash)
</ToastProvider>
</CartProvider>
</ThemeProvider>
</AuthProvider>
YECHIM — Provider'larni BIRLASHTIRISH (compose):
const providers = [AuthProvider, ThemeProvider, CartProvider, ToastProvider];
function AppProviders({ children }) {
return providers.reduceRight(
(acc, Provider) => <Provider>{acc}</Provider>, // o'ngdan chapga o'rab boradi
children
);
}
// <AppProviders><App /></AppProviders> — yassi, toza
┌────────────────────────────────────────────────────────────┐
│ Provider hell: 5+ ichma-ich (chalkash) compose (yassi) │
│ yoki React Context'ni mantiqiy guruhlash (auth+user birga) │
└────────────────────────────────────────────────────────────┘
Ko'p Provider compose funksiyasi (ichma-ich piramidadan qochish)
Yoki bog'liq Context'larni birlashtirish (auth+permissions — bitta Provider)Provider kompozitsiyasi (provider hell) — ko'p Context'ning amaliy muammosini hal qiladi. Muammo: real ilovada ko'p Provider bo'ladi (auth, theme, cart, toast, query...) — ular
main.tsx/App'da ichma-ich joylansa (<AuthProvider><ThemeProvider><CartProvider>...), bu "provider hell" (piramida) — chalkash, qatlamlar ko'payganda o'qish qiyin. Yechim — Provider'larni birlashtirish (compose):providers.reduceRight((acc, Provider) => <Provider>{acc}</Provider>, children)— massivdagi Provider'larni o'ngdan chapga (reduceRight) bir-birini o'rab boradi, natijada<AppProviders><App /></AppProviders>(yassi, toza). Ikki nuqta: (1) ko'p Provider bo'lsa — compose funksiyasi (ichma-ich piramidadan qochish — toza arxitektura); (2) yoki mantiqiy bog'liq Context'larni birlashtirish (masalan auth + permissions — bittaAuthProviderda — chunki ular birga ishlatiladi). Eslatma: Provider tartibi muhim bo'lishi mumkin (masalan auth router ichida bo'lishi kerak — 11.15: Misol 14). Bu — ko'p Context'li ilovani toza tutishning amaliy usuli.
2.8.1. Context compound komponentlarda (11.13 davomi)
CONTEXT'ning YANA BIR muhim ishlatilishi — COMPOUND komponent 11.13-bob:
bog'liq komponentlar (masalan <Tabs>, <Tabs.List>, <Tabs.Panel>) o'zaro
holatni PROPS orqali emas, ICHKI Context orqali baham ko'radi:
<Tabs value={active} onChange={setActive}> {/* Tabs ichida TabsContext.Provider */}
<Tabs.List>
<Tabs.Tab id="a">Birinchi</Tabs.Tab> {/* ichki Context'dan active/onChange oladi */}
<Tabs.Tab id="b">Ikkinchi</Tabs.Tab>
</Tabs.List>
<Tabs.Panel id="a">...</Tabs.Panel>
</Tabs>
Foydalanuvchi <Tabs.Tab>'ga "active"/"onChange" props uzatmaydi (ichki Context uzatadi)
Bu "ichki" (private) Context — tashqariga export QILINMAYDI (faqat komponent oilasi ishlatadi)
Compound komponentda Context — komponentlararo aloqa (props drilling'siz — ichki API)
Bu Context ODATDA memo/split kerak emas (kichik, kam consumer — 11.13'da chuqur)Context compound komponentlarda — Context'ning ilova-darajasidagi global holatdan (auth/theme) tashqari, ikkinchi muhim ishlatilishi (11.13 davomi). Compound komponent — bir-biriga bog'liq bir nechta komponentdan iborat "oila" (masalan
<Tabs>,<Accordion>,<Select>); ular umumiy holatni (qaysi tab faol, qaysi element ochiq) props orqali emas, ichki Context orqali baham ko'radi. Ota-komponent (<Tabs>) o'z ichidaTabsContext.Providerni joylashtiradi va holatni beradi; bola-komponentlar (<Tabs.Tab>,<Tabs.Panel>)useContextbilan uni to'g'ridan oladi — natijada foydalanuvchi bolalargaactive/onChangekabi props'ni qo'lda uzatmaydi (ichki API buni yashiradi — deklarativ, toza). Ikki nuqta: (1) bu — Context'ning komponentlararo (ilova emas) ishlatilishi: bir komponent oilasi ichida props drilling'ni yo'qotadi; (2) bu Context ichki (private) — tashqariga export qilinmaydi (faqat komponent oilasi ishlatadi), va odatda kichik/kam consumer bo'lgani uchun value memo/split kabi optimizatsiyalar kritik emas (compound naqshi 11.13'da chuqur ko'rilgan). Demak, Context ikki xil miqyosda ishlaydi: global (auth/theme/i18n — butun ilova) va lokal (compound komponent — bitta oila).
2.9. Performance tuzoqlari va selektor naqshi
CONTEXT PERFORMANCE TUZOQLARI va YECHIMLARI:
1. value har render yangi useMemo 2.4-bob
2. bitta katta Context bo'lish (state/dispatch, mavzu — 2.6)
3. tez-tez o'zgaradigan katta state Context EMAS (selektor yo'q — 2.3)
SELEKTOR MUAMMOSI: useContext butun value'ni oladi (qismini tinglab bo'lmaydi):
const { user } = useContext(AppContext); // theme o'zgarsa ham BU re-render (user kerak edi)
YECHIMLAR:
Context'ni bo'lish (har qism alohida — 2.6)
use-context-selector kutubxonasi (qism tinglash — Context'ga selektor qo'shadi):
const user = useContextSelector(AppContext, (s) => s.user); // faqat user o'zgarsa render
Katta/murakkab state Zustand 12.5-bob yoki Redux 12.2-bob — TABIIY selektor
┌────────────────────────────────────────────────────────────┐
│ Context: selektor yo'q (butun value) bo'lish yoki kutubxona│
│ Zustand/Redux: tabiiy selektor (qism tinglash — afzal kattada)│
└────────────────────────────────────────────────────────────┘
Context'ning asosiy cheklovi — SELEKTOR yo'q (qism tinglab bo'lmaydi — 2.3)
Katta, tez o'zgaradigan state Zustand/Redux (selektor — kerakli render — 2.10)Performance tuzoqlari va selektor — Context'ning cheklovlarini va yechimlarini umumlashtiradi. Uch asosiy tuzoq va yechim: (1) value har render yangi
useMemo2.4-bob; (2) bitta katta Context bo'lish (state/dispatch, mavzu — 2.6); (3) tez-tez o'zgaradigan katta state Context emas (chunki selektor yo'q — 2.3). Selektor muammosi — Context'ning tub cheklovi:useContextbutun value'ni oladi, uning qismini "tinglab" bo'lmaydi (const { user } = useContext(AppContext)—themeo'zgarsa ham bu komponent re-render bo'ladi, garchi faqatuserkerak edi). Yechimlar: (a) Context'ni bo'l 2.6-bob; (b)use-context-selectorkutubxonasi — Context'ga selektor qo'shadi (useContextSelector(AppContext, (s) => s.user)— faqatusero'zgarganda render); (c) katta/murakkab state uchun Zustand 12.5-bob yoki Redux 12.2-bob — bularda selektor tabiiy (useStore(s => s.user)). Ikki nuqta: (1) Context'ning asosiy cheklovi — selektor yo'q (qism tinglab bo'lmaydi); (2) katta, tez o'zgaradigan state uchun Zustand/Redux afzal (selektor — faqat kerakli komponent re-render). Bu — Context vs Redux/Zustand qaror 2.10-bobning asosiy dalili.
2.10. Qachon Context, qachon Redux/Zustand/Query
TO'G'RI VOSITANI TANLASH (eng muhim qaror):
┌─────────────────────────┬──────────────────────────────────┐
│ Ehtiyoj │ Vosita │
├─────────────────────────┼──────────────────────────────────┤
│ Kam o'zgaradigan global │ Context (theme, auth, locale) │
│ (theme/auth/i18n) │ (oddiy, o'rnatilgan — 2.7) │
│ Kichik global state │ Context + useReducer (mini-Redux) │
│ Katta/murakkab/tez state│ Zustand 12.5-bob yoki Redux 12.2-bob │
│ (selektor kerak) │ (tabiiy selektor — 2.9) │
│ SERVER ma'lumoti │ TanStack Query / RTK Query (12.3/4)│
│ (API, kesh, sync) │ Redux/Context EMAS (server ≠ client)│
│ Forma holati │ React Hook Form 11.10-bob │
│ URL holati (filtr) │ useSearchParams 11.9-bob │
└─────────────────────────┴──────────────────────────────────┘
ENG KENG XATO: server ma'lumotini (API javobi) Redux/Context'da saqlash
server ma'lumoti — TanStack Query/RTK Query (kesh/sync avtomatik — 12.4)
Client state (UI, theme, auth) ≠ Server state (API ma'lumoti) — HAR XIL vositaQachon Context, qachon Redux/Zustand/Query — state management'ning eng muhim qarori. To'g'ri vositani tanlash ehtiyojga bog'liq: (1) kam o'zgaradigan global (theme, auth, locale/i18n) Context (oddiy, o'rnatilgan — 2.7); (2) kichik global state Context + useReducer (mini-Redux — 2.7); (3) katta/murakkab/tez o'zgaradigan state (selektor kerak) Zustand 12.5-bob yoki Redux 12.2-bob — tabiiy selektor 2.9-bob; (4) server ma'lumoti (API javobi, kesh, sinxronlash) TanStack Query / RTK Query (12.3/12.4) — Redux/Context emas!; (5) forma holati React Hook Form 11.10-bob; (6) URL holati (filtr, sahifa)
useSearchParams11.9-bob. Eng keng xato: server ma'lumotini (API javobini) Redux yoki Context'da saqlash — bu noto'g'ri, chunki server ma'lumoti o'z muammolariga ega (kesh, fonda yangilash, eskirish, qayta urinish) va ularni TanStack/RTK Query avtomatik hal qiladi 12.4-bob; Redux/Context'ga qo'lda saqlash — ko'p qo'lda kod va xato. Client state (UI, theme, auth — brauzerda tug'iladi) va server state (API ma'lumoti — serverdan keladi) — har xil muammo, har xil vosita. Bu farqni anglash — zamonaviy frontend arxitekturasining eng muhim tushunchasidan biri (va 12-QISM'ning markaziy g'oyasi).
2.11. Server Components va Context (Next.js — qisqa)
NEXT.JS (13) — Server Components 13.3-bob Context'ni TO'G'RIDAN ISHLATA OLMAYDI:
- Server Component — server'da render (state/effect/Context yo'q — 13.3)
- Context — CLIENT mexanizmi (brauzerda — interaktiv)
Server Component'da useContext ISHLATIB BO'LMAYDI (xato)
YECHIM (Next.js'da):
Provider'ni "use client" komponentga o'rab, layout'da ishlatish:
// providers.tsx
"use client";
export function Providers({ children }) { return <ThemeProvider>{children}</ThemeProvider>; }
Context faqat CLIENT Component'larda (interaktiv qism)
Server ma'lumoti — Context'da emas, props yoki Server Component'da (13.5)
Context — client mexanizmi (Next.js Server Component'da ishlamaydi — "use client" kerak)
13-QISM (Next.js)da Context'ni to'g'ri joylashtirish (client chegarasi) — chuqurServer Components va Context — Next.js konteksti (13-QISM oldindan ko'rinishi). Next.js'ning Server Components 13.3-bob — server'da render bo'ladigan komponentlar; ularda state, effect, va Context yo'q (chunki bular client/interaktiv mexanizmlar). Shuning uchun Server Component'da
useContextishlatib bo'lmaydi (xato beradi). Yechim (Next.js'da): (1) Provider'ni"use client"direktivali komponentga o'rab, root layout'da ishlatish (Providers— barcha Context'larni client tomonda beradi); (2) Context faqat Client Component'larda ("use client"— interaktiv qism); (3) server ma'lumotini Context'da emas, props orqali yoki Server Component'ning o'zida olish (13.5 — data fetching). Ikki nuqta: (1) Context — client mexanizmi (Next.js Server Component'da ishlamaydi —"use client"chegarasi kerak); (2) 13-QISM (Next.js)da Context'ni to'g'ri joylashtirish (server/client chegarasi) chuqurroq o'rganiladi. Hozircha bilish kerak: Context — brauzer (client) tushunchasi; SSR/Server Components muhitida uni ehtiyotkorlik bilan joylashtirish kerak. Bu — Next.js'ga o'tganda muhim bo'ladigan nozik nuqta.
3. Sintaksis — tez ma'lumotnoma
YARATISH 2.2-bob: const Ctx = createContext(defaultValue | null)
PROVIDER 2.2-bob: <Ctx.Provider value={value}>{children}</Ctx.Provider>
O'QISH 2.2-bob: const value = useContext(Ctx)
VALUE MEMO 2.4-bob: const value = useMemo(() => ({ a, b }), [a, b])
CUSTOM HOOK 2.5-bob: function useX() { const c = useContext(Ctx); if(!c) throw...; return c }
BO'LISH 2.6-bob: StateContext + DispatchContext (state o'qish / dispatch yozish alohida)
REDUCER 2.7-bob: useReducer(reducer, initial) + Context'ga state/dispatch ber
COMPOSE 2.8-bob: providers.reduceRight((acc, P) => <P>{acc}</P>, children)
SELEKTOR 2.9-bob: useContextSelector(Ctx, s => s.user) // use-context-selector
QAROR 2.10-bob: kam o'zgaradiganContext | katta/tezZustand/Redux | serverQuery4. Batafsil kod namunalari
Misol 1 — Asosiy Context (theme — 2.2)
import { createContext, useContext, useState, useMemo } from "react";
const ThemeContext = createContext<{ theme: string; toggle: () => void } | null>(null);
export function ThemeProvider({ children }: React.PropsWithChildren) {
const [theme, setTheme] = useState("light");
const toggle = () => setTheme((t) => (t === "light" ? "dark" : "light"));
const value = useMemo(() => ({ theme, toggle }), [theme]); // barqaror value (2.4)
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
}
export function useTheme() {
const ctx = useContext(ThemeContext);
if (!ctx) throw new Error("useTheme ThemeProvider ichida ishlatilishi kerak");
return ctx;
}
// Ishlatish:
function ThemeButton() {
const { theme, toggle } = useTheme();
return <button onClick={toggle}>Mavzu: {theme}</button>;
}Misol 2 — Value memo (re-render tuzog'i — 2.4)
// Har render yangi value (consumer'lar har render render):
function BadProvider({ children }: React.PropsWithChildren) {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider value={{ user, setUser }}> {/* HAR render yangi obyekt! */}
{children}
</AuthContext.Provider>
);
}
// useMemo bilan barqaror:
function GoodProvider({ children }: React.PropsWithChildren) {
const [user, setUser] = useState(null);
const value = useMemo(() => ({ user, setUser }), [user]); // user o'zgargandagina
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
// Bad: har render consumer render; Good: user o'zgargandagina (2.4)Misol 3 — Context bo'lish (state + dispatch — 2.6)
import { createContext, useContext, useReducer } from "react";
const CartStateContext = createContext<CartItem[] | null>(null);
const CartDispatchContext = createContext<React.Dispatch<CartAction> | null>(null);
function cartReducer(state: CartItem[], action: CartAction): CartItem[] {
switch (action.type) {
case "add": return [...state, action.payload];
case "remove": return state.filter((i) => i.id !== action.payload);
case "clear": return [];
default: return state;
}
}
export function CartProvider({ children }: React.PropsWithChildren) {
const [cart, dispatch] = useReducer(cartReducer, []);
return (
<CartDispatchContext.Provider value={dispatch}> {/* dispatch barqaror — re-render yo'q */}
<CartStateContext.Provider value={cart}>{children}</CartStateContext.Provider>
</CartDispatchContext.Provider>
);
}
export function useCart() {
const ctx = useContext(CartStateContext);
if (ctx === null) throw new Error("useCart CartProvider ichida");
return ctx;
}
export function useCartDispatch() {
const ctx = useContext(CartDispatchContext);
if (!ctx) throw new Error("useCartDispatch CartProvider ichida");
return ctx;
}
// Faqat dispatch'ni ishlatgan tugma — cart o'zgarganda RE-RENDER BO'LMAYDI (2.6)Misol 4 — Context + useReducer ishlatish (2.7)
// Mahsulot qo'shadigan tugma — FAQAT dispatch (state o'qimaydi cart o'zgarganda render yo'q):
function AddButton({ product }: { product: Product }) {
const dispatch = useCartDispatch(); // faqat dispatch
return <button onClick={() => dispatch({ type: "add", payload: product })}>Savatga</button>;
}
// Savat soni — cart'ni o'qiydi (cart o'zgarganda render — to'g'ri):
function CartBadge() {
const cart = useCart(); // o'qiydi
return <span> {cart.length}</span>;
}
// AddButton dispatch'ni, CartBadge state'ni — ajratilgan (AddButton bekorga render bo'lmaydi)Misol 5 — Provider kompozitsiyasi (compose — 2.8)
const providers = [QueryProvider, ThemeProvider, AuthProvider, CartProvider, ToastProvider];
function AppProviders({ children }: React.PropsWithChildren) {
return providers.reduceRight(
(acc, Provider) => <Provider>{acc}</Provider>, // o'ngdan chapga o'rab boradi
children
) as React.ReactElement;
}
// main.tsx:
// <AppProviders><App /></AppProviders> — ichma-ich piramida o'rniga yassi
// 5 Provider — bitta AppProviders (provider hell'dan qoch — 2.8)Misol 6 — i18n (til) Context (real naqsh — 2.7)
type Lang = "uz" | "ru" | "en";
const translations = {
uz: { welcome: "Xush kelibsiz", login: "Kirish" },
en: { welcome: "Welcome", login: "Login" },
ru: { welcome: "Dobro pojalovat", login: "Vxod" },
};
const I18nContext = createContext<{ lang: Lang; t: (key: string) => string; setLang: (l: Lang) => void } | null>(null);
export function I18nProvider({ children }: React.PropsWithChildren) {
const [lang, setLang] = useState<Lang>("uz");
const t = useCallback((key: string) => translations[lang][key] ?? key, [lang]);
const value = useMemo(() => ({ lang, t, setLang }), [lang, t]);
return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>;
}
export const useI18n = () => {
const ctx = useContext(I18nContext);
if (!ctx) throw new Error("useI18n I18nProvider ichida");
return ctx;
};
// Ishlatish:
function Header() {
const { t, setLang } = useI18n();
return <h1>{t("welcome")}</h1>; // tilga qarab matn
}Misol 7 — Toast Context (bildirishnoma — 2.7)
interface Toast { id: string; message: string; type: "success" | "error"; }
const ToastContext = createContext<{ toasts: Toast[]; show: (m: string, t?: "success" | "error") => void } | null>(null);
export function ToastProvider({ children }: React.PropsWithChildren) {
const [toasts, setToasts] = useState<Toast[]>([]);
const show = useCallback((message: string, type: "success" | "error" = "success") => {
const id = crypto.randomUUID();
setToasts((prev) => [...prev, { id, message, type }]);
setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), 3000); // 3s'da yo'qol
}, []);
const value = useMemo(() => ({ toasts, show }), [toasts, show]);
return (
<ToastContext.Provider value={value}>
{children}
<div className="toast-container">{toasts.map((t) => <div key={t.id} className={t.type}>{t.message}</div>)}</div>
</ToastContext.Provider>
);
}
export const useToast = () => useContext(ToastContext)!;
// Ishlatish: const { show } = useToast(); show("Saqlandi", "success");Misol 8 — use-context-selector (qism tinglash — 2.9)
import { createContext, useContextSelector } from "use-context-selector";
const AppContext = createContext<AppState | null>(null);
// Faqat user o'zgarganda render (theme o'zgarsa — bu render BO'LMAYDI):
function UserName() {
const user = useContextSelector(AppContext, (state) => state?.user); // selektor
return <span>{user?.name}</span>;
}
// Faqat theme o'zgarganda render:
function ThemeIndicator() {
const theme = useContextSelector(AppContext, (state) => state?.theme);
return <span>{theme}</span>;
}
// use-context-selector — Context'ga selektor qo'shadi (qism tinglash — re-render kamayadi — 2.9)
// Lekin: katta state uchun Zustand 12.5-bob tabiiyroq (built-in selektor)Misol 9 — Nested Context (ichki Provider — 2.2)
const ThemeContext = createContext("light");
function App() {
return (
<ThemeContext.Provider value="dark"> {/* tashqi: dark */}
<Header /> {/* dark */}
<ThemeContext.Provider value="light"> {/* ichki: light (g'olib) */}
<Sidebar /> {/* light (eng yaqin Provider) */}
</ThemeContext.Provider>
</ThemeContext.Provider>
);
}
// useContext eng YAQIN Provider'ni oladi (Sidebar light, Header dark — 2.2)Misol 10 — Context performance test (re-render ko'rsatish — 2.3)
// Bitta katta Context — har bo'lak o'zgarsa hamma render (yomon):
const BadContext = createContext<{ user: User; theme: string; cart: Item[] } | null>(null);
// Bo'lingan — har bo'lak alohida (yaxshi):
const UserContext = createContext<User | null>(null);
const ThemeContext = createContext<string>("light");
const CartContext = createContext<Item[]>([]);
function GoodProviders({ children }: React.PropsWithChildren) {
// har bo'lak alohida Provider — biri o'zgarsa boshqasini ishlatgan komponent tegmaydi
return (
<UserProvider><ThemeProvider><CartProvider>{children}</CartProvider></ThemeProvider></UserProvider>
);
}
// Bad: cart o'zgarsa user/theme consumer ham render; Good: faqat cart consumer (2.3, 2.6)Misol 11 — Type-safe Context factory (qayta ishlatiladigan — 11.14)
// Generic Context yaratuvchi yordamchi (null tekshiruvni bir marta yozish):
function createSafeContext<T>(name: string) {
const Context = createContext<T | null>(null);
function useSafeContext() {
const ctx = useContext(Context);
if (ctx === null) throw new Error(`use${name} must be used within ${name}Provider`);
return ctx;
}
return [useSafeContext, Context.Provider] as const;
}
// Ishlatish — null tekshiruv avtomatik:
const [useAuth, AuthProviderRaw] = createSafeContext<AuthValue>("Auth");
// Har Context uchun null tekshiruvni takrorlamaslik (DRY + type-safe — 11.14)Misol 12 — Context vs Query (server ma'lumoti — 2.10)
// NOTO'G'RI — server ma'lumotini Context'da saqlash (qo'lda kesh/sync — og'riq):
function BadUsersProvider({ children }: React.PropsWithChildren) {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => { fetch("/api/users").then(r => r.json()).then(d => { setUsers(d); setLoading(false); }); }, []);
// kesh yo'q, qayta yuklash qo'lda, eskirish boshqarilmaydi (2.10)
return <UsersContext.Provider value={{ users, loading }}>{children}</UsersContext.Provider>;
}
// TO'G'RI — server ma'lumoti TanStack Query 12.4-bob:
function UsersList() {
const { data: users, isLoading } = useQuery({ queryKey: ["users"], queryFn: () => fetch("/api/users").then(r => r.json()) });
// kesh, fonda yangilash, qayta urinish AVTOMATIK (12.4)
if (isLoading) return <Spinner />;
return <ul>{users.map((u: User) => <li key={u.id}>{u.name}</li>)}</ul>;
}
// Server ma'lumoti — Query (Context emas); client state (theme/auth) — Context (2.10)Misol 13 — Disclosure Context (modal/drawer boshqaruvi — 2.7)
// Global modal boshqaruvi (istalgan joydan ochish):
const ModalContext = createContext<{ open: (content: React.ReactNode) => void; close: () => void } | null>(null);
export function ModalProvider({ children }: React.PropsWithChildren) {
const [content, setContent] = useState<React.ReactNode>(null);
const open = useCallback((c: React.ReactNode) => setContent(c), []);
const close = useCallback(() => setContent(null), []);
const value = useMemo(() => ({ open, close }), [open, close]); // open/close barqaror
return (
<ModalContext.Provider value={value}>
{children}
{content && <Modal onClose={close}>{content}</Modal>} {/* 11.12 portal */}
</ModalContext.Provider>
);
}
export const useModal = () => useContext(ModalContext)!;
// Ishlatish: const { open } = useModal(); open(<ProductForm />); — istalgan joydan modalMisol 14 — To'liq auth Context (production naqsh — 2.5)
interface AuthValue {
user: User | null;
isLoading: boolean;
login: (email: string, password: string) => Promise<void>;
logout: () => void;
}
const AuthContext = createContext<AuthValue | null>(null);
export function AuthProvider({ children }: React.PropsWithChildren) {
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => { // mount'da token'dan tikla (11.15: 2.5)
const token = localStorage.getItem("token");
if (!token) { setIsLoading(false); return; }
api.get("/auth/me").then((r) => setUser(r.data)).catch(() => localStorage.removeItem("token")).finally(() => setIsLoading(false));
}, []);
const login = useCallback(async (email: string, password: string) => {
const { data } = await api.post("/auth/login", { email, password });
localStorage.setItem("token", data.token);
setUser(data.user);
}, []);
const logout = useCallback(() => { localStorage.removeItem("token"); setUser(null); }, []);
const value = useMemo(() => ({ user, isLoading, login, logout }), [user, isLoading, login, logout]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
export function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error("useAuth AuthProvider ichida ishlatilishi kerak");
return ctx;
}
// value memo + custom hook + persist + null tekshiruv — to'liq auth Context (2.4, 2.5)5. To'g'ri va noto'g'ri holatlar
1) Provider value
value={{ user, setUser }} (har render yangi consumer render — 2.4)
value={useMemo(() => ({ user, setUser }), [user])}2) Context tashkili
useContext(Ctx) har komponentda + null tekshiruv (takror)
custom hook (useAuth — qulay, xavfsiz — 2.5)3) Katta tez state
tez-tez o'zgaradigan katta state Context'da (selektor yo'q — ko'p render — 2.3)
Zustand/Redux (tabiiy selektor — 2.9, 2.10)4) Server ma'lumoti
API ma'lumotini Context/Redux'da (qo'lda kesh/sync — 2.10)
TanStack/RTK Query (avtomatik kesh — 12.4)5) Provider hell
6 Provider ichma-ich piramida (chalkash — 2.8)
compose funksiyasi (yassi)6) Re-render
bitta katta Context (har bo'lak hamma'ni render — 2.3)
bo'lish (state/dispatch, mavzu — 2.6)6. Keng tarqalgan xatolar va yechimlari
Xato 1 — Consumer har render re-render bo'ladi (sekin)
Sababi: Provider value har render yangi obyekt 2.4-bob. Yechimi: useMemo bilan value'ni barqarorlashtiring.
Xato 2 — Cannot read properties of null (useContext)
Sababi: komponent Provider tashqarisida, value null 2.5-bob. Yechimi: Provider'ni yuqorida o'rang; custom hook'da if (!ctx) throw.
Xato 3 — Context o'zgardi, lekin komponent yangilanmaydi
Sababi: value obyekti mutatsiya qilindi (yangi havola yo'q — 11.6: 2.9). Yechimi: yangi obyekt ({...prev}); state'ni to'g'ri yangilang.
Xato 4 — Bitta o'zgarish butun ilovani sekinlashtiradi
Sababi: bitta katta Context, ko'p consumer 2.3-bob. Yechimi: Context'ni bo'lish 2.6-bob, yoki selektor 2.9-bob, yoki Zustand.
Xato 5 — useContext is not a function / Server Component xatosi
Sababi: Next.js Server Component'da Context ishlatildi 2.11-bob. Yechimi: "use client" direktivasi; Provider'ni client komponentga o'rang (13).
Xato 6 — Server ma'lumoti eskirgan (Context'da)
Sababi: API ma'lumoti Context'da, sync yo'q 2.10-bob. Yechimi: TanStack Query (avtomatik refetch/kesh — 12.4).
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- Hooks (11.5, 11.6, 11.7): useContext, useReducer, useMemo, custom hook — Context'ning asoslari.
- Performance 11.11-bob: Context re-render — performance muammosi (bo'lish, selektor).
- Redux Toolkit 12.2-bob: Context + useReducer — Redux'ning kichik modeli.
- Zustand 12.5-bob: Context muammolarini (selektor, re-render) tabiiy hal qiladi.
- TanStack/RTK Query (12.3, 12.4): server ma'lumoti — Context emas, Query.
- Dashboard 11.15-bob: auth/theme Context (provider tartibi).
- Next.js 13.3-bob: Server Components va Context ("use client" chegarasi).
- TypeScript 11.14-bob: type-safe Context (createContext<T | null>).
8. Eng yaxshi amaliyotlar (best practices)
- value'ni
useMemo(har render yangi obyekt — eng keng tuzoq — 2.4). - Custom hook bilan o'rash (useAuth — qulay, xavfsiz, type-safe — 2.5).
- Context'ni bo'lish (state/dispatch, mavzu — re-render kamaytirish — 2.6).
- Context + useReducer (kichik global state — mini-Redux — 2.7).
- Provider'larni compose qilish (provider hell'dan qochish — 2.8).
- Server ma'lumotini Context'da saqlamaslik (TanStack Query — 2.10).
- Katta/tez state Zustand/Redux (selektor — 2.9, 2.10).
- Type-safe Context (
createContext<T | null>+ null tekshiruv — 11.14). - Context obyektini export qilmaslik (faqat hook + Provider — interfeys nazorati — 2.5).
- To'g'ri vositani tanlash (client vs server state — 2.10).
9. Amaliy loyiha: "Global Holat Tizimi (Context)"
Context'ni chuqur, to'g'ri va optimal ishlatishni mustahkamlash.
Maqsad
Ilova uchun bir nechta global Context yarat (auth, theme, i18n, toast, cart) — har biri to'g'ri optimallashtirilgan, bo'lingan, type-safe.
Talablar (requirements)
- Auth Context: user, login, logout, isLoading, persist (Misol 14, 2.5).
- Theme Context: dark/light, persist (Misol 1).
- i18n Context: uz/ru/en, t() funksiyasi (Misol 6).
- Toast Context: show(), avtomatik yo'qolish (Misol 7).
- Cart Context: useReducer bilan, state/dispatch ajratilgan (Misol 3, 4, 2.6).
- value memo: har Provider value'si barqaror (Misol 2, 2.4).
- Custom hook: har Context uchun useX hook + null tekshiruv (Misol 11, 2.5).
- Compose: Provider'larni AppProviders'da birlashtirish (Misol 5, 2.8).
- Selektor (bonus): kamida bitta katta Context'da use-context-selector (Misol 8, 2.9).
- Server ma'lumotini Context'da SAQLAMASLIK: API — Query (keyingi bob — 2.10).
Maslahatlar (hint)
- value'ni doim useMemo bilan (Xato 1, 2.4).
- Cart — useReducer + state/dispatch ajratish (tugma re-render bo'lmasin — 2.6).
- Custom hook + null tekshiruv (Provider tashqarisida — aniq xato — 2.5).
- Provider hell — compose (Misol 5, 2.8).
- Server ma'lumoti (mahsulotlar) — Context'da emas, Query'ga qoldirish 2.10-bob.
- React DevTools Profiler bilan re-render'ni tekshirish (bo'lish foyda berdimi — 11.11).
"Tayyor" mezonlari (acceptance criteria)
- Auth/theme/i18n/toast/cart Context'lari ishlaydi.
- Har value useMemo bilan barqaror.
- Cart state/dispatch ajratilgan (dispatch komponenti re-render bo'lmaydi).
- Har Context custom hook + null tekshiruv.
- Provider'lar compose bilan (yassi).
- Type-safe (createContext<T | null>).
- Profiler — keraksiz re-render yo'q (bo'lish ishladi).
- Server ma'lumoti Context'da saqlanmaydi (Query'ga qoldirilgan).
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda Context API'ni chuqur o'rgandik:
- Props drilling 2.1-bob; Context arxitekturasi (createContext/Provider/useContext — ichki mexanizm — 2.2); re-render xulqi (eng muhim — 2.3); value barqarorligi (memo — 2.4).
- Custom hook 2.5-bob; Context bo'lish (state/dispatch — 2.6); Context + useReducer (mini-Redux — 2.7); provider kompozitsiyasi 2.8-bob.
- Performance va selektor 2.9-bob; qachon Context/Redux/Zustand/Query (eng muhim qaror — 2.10); Server Components (Next.js — 2.11).
Endi siz Context'ni to'g'ri (value memo, custom hook), optimal (bo'lish, selektor), va o'rinli (qachon Context, qachon boshqa vosita) ishlata olasiz. Eng muhimi — client state vs server state farqini va vosita tanlovini tushunasiz. Bu — state management mavzusining poydevori.
Keyingi bob — 12.2-bob: Redux Toolkit (store, slice, async thunk). Context kichik global state uchun yetadi, lekin katta, murakkab ilovada (ko'p bog'liq state, murakkab yangilanish, DevTools/debugging ehtiyoji) — Redux kerak. Redux Toolkit (RTK) — Redux'ning zamonaviy, sodda usuli (eski Redux'ning boilerplate'ini yo'qotadi): store, slice (reducer + action avtomatik), Immer (mutatsiya sintaksisi, immutable natija), useSelector/useDispatch (tabiiy selektor — Context cheklovini hal qiladi), va createAsyncThunk (async — loading/error). Bu — katta ilovaning markaziy holat boshqaruvi.
Foydalanilgan rasmiy/ishonchli manbalar
- React rasmiy hujjati (react.dev):
useContext— API ma'lumotnomasi (Provider, default qiymat, consumer xulqi).createContext— kontekst yaratish va TypeScript bilan tiplash.- "Passing Data Deeply with Context" — props drilling muammosi va Context yechimi.
- "Scaling Up with Reducer and Context" — Context + useReducer (mini-global-store) naqshi.
- "Managing State" bo'limi — qachon lokal state, qachon Context, holatni ko'tarish (lifting state up).
- use-context-selector — Context'ga selektor qo'shuvchi kutubxona rasmiy hujjati (qism tinglash, re-render kamaytirish).
- TanStack Query rasmiy hujjati — client state va server state farqi (server ma'lumotini Context'da saqlamaslik sababi — 12.4 bilan bog'liq).
- TypeScript + React rasmiy tavsiyalari —
createContext<T | null>va type-safe custom hook naqshi.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!