11.6-bob: useMemo, useCallback, useReducer
11-QISM — Frontend: React · 6-mavzu
1. Kirish va motivatsiya
11.5-bobda to'rtta asosiy hookni o'rgandik. Endi hooklar bilimini yana uchta muhim hook bilan yakunlaymiz — va bu uchchovi ikkita katta mavzuga bo'linadi. Birinchisi — useReducer — useStatening kuchliroq, tartibliroq ukasi: u murakkab, bir-biriga bog'liq state mantig'ini bitta markaziy joyda boshqaradi va bevosita Redux falsafasiga 12.2-bob ko'prik bo'ladi. Ikkinchisi — useMemo va useCallback — bular memoizatsiya (keshlash) hooklari: ular React'ning keraksiz qayta hisoblash va qayta render'larini to'xtatish uchun ishlatiladi, ya'ni performance optimizatsiyasi 11.11-bob ning poydevori.
Lekin bu yerda eng muhim narsa — balans. useMemo va useCallback "tezroq" degan so'zni eshitib, ko'p junior dasturchi ularni hamma joyga tiqishtiradi — bu xato. Ortiqcha memoizatsiya kodni murakkablashtiradi va ba'zan sekinlashtiradi (keshlash ham bepul emas). Shuning uchun bu bobda biz nafaqat "qanday ishlatish"ni, balki eng muhimi — qachon kerak va qachon kerak EMASligini chuqur o'rganamiz. Bundan tashqari, 2025-yilda chiqqan React Compiler (React 19 bilan) bu hooklarning ko'p ishlatilishini avtomatik qiladi — bu kontekstni ham tushunamiz, chunki u kod yozish uslubiga ta'sir qiladi.
Bu bob: useReducer (nima, nega, reducer funksiya — (state, action) => newState, dispatch, action type/payload, lazy init, useState bilan solishtirish, Redux'ga ko'prik), memoizatsiya (keshlash g'oyasi), useMemo (qimmat hisobni keshlash + referential equality — obyekt/massiv havolasini barqaror ushlash, bu 11.5: 2.9 dagi object-dependency tuzog'ini hal qiladi), useCallback (funksiyani keshlash — React.memo'li bola va effekt deps uchun), React.memo bilan bog'lanish (props o'zgarmasa render qilmaslik), qachon optimallashtirMAslik (o'lchamasdan optimallashtirma — premature optimization), va React Compiler (avto-memoizatsiya — kelajak). Bundan tashqari, senior bo'lish uchun shart — referential equality, memoizatsiyaning "narxi", va React Compiler — chuqur qamraladi.
O'xshatish:
useReducer— bu bank operatorlari oynasi.useStateda har bir mijoz (komponent) o'zi to'g'ridan-to'g'ri pulni (state) o'zgartiradi — kichik do'konda mayli. Lekin katta bankda hamma o'z xohlaganini qilsa — tartibsizlik.useReducerda esa bitta oyna (reducer) bor: mijoz "men 100 so'm yechmoqchiman" degan so'rov (action) yuboradi, operator (reducer) qoidalarni tekshirib, hisobni (state) o'zgartiradi. Barcha o'zgarishlar bitta joydan, bitta mantiqdan o'tadi — tartibli, bashoratli, sinash oson.useMemo/useCallbackesa — hisob-kitob daftaringga yozib qo'yish: ag'ar bir qiyin masalani yechgan bo'lsangiz (2 soat ishladi), javobini daftarga yozasiz; keyingi safar o'sha masala kelsa — qaytadan yechmaysiz, daftardan o'qiysiz (kesh). Lekin har bir oddiy masalani ("2+2") ham daftarga yozib o'tirsangiz — daftar to'lib ketadi, qidirish o'zi vaqt oladi (ortiqcha memoizatsiya zarari).
Nega muhim?
- Murakkab state — real ilovada (forma, savat, wizard)
useStateyetmaydi;useReducertartib beradi. - Performance —
useMemo/useCallback— 11.11 (optimizatsiya)ning asosiy vositalari. - Referential equality — React'ning eng nozik tushunchasi; uni bilmasdan memoizatsiya ishlamaydi (11.5: 2.9 tuzog'i).
- Redux'ga ko'prik —
useReducer— Redux 12.2-bobning kichik modeli; uni tushunsangiz, Redux oson.
2. Nazariya — chuqur tushuntirish
2.1. Nega bu uch hook — re-render va keshlash
IKKI MUAMMO bu uch hook hal qiladi:
MUAMMO A — MURAKKAB STATE (useReducer):
Ko'p bog'liq state + ko'p o'zgartirish usuli = useState'lar tarqoq, chalkash
useReducer: barcha o'zgarish mantig'i BITTA reducer'da (tartib)
MUAMMO B — KERAKSIZ QAYTA HISOB / RENDER (useMemo, useCallback):
Har render'da:
- qimmat hisob qaytadan bajariladi (1000 element saralash — har marta)
- yangi obyekt/funksiya yaratiladi (yangi havola bola keraksiz re-render — 11.5: 2.9)
useMemo: hisob natijasini KESHLA; useCallback: funksiyani KESHLA
┌────────────┬──────────────────────────────────────────────┐
│ useReducer │ murakkab state mantiqini markazlashtirish │
│ useMemo │ qimmat HISOB natijasini keshlash │
│ useCallback│ FUNKSIYA havolasini keshlash (barqaror) │
└────────────┴──────────────────────────────────────────────┘
useReducer — TARTIB uchun; useMemo/useCallback — TEZLIK (referential barqarorlik) uchunNega bu uch hook — ular ikki xil muammoni hal qiladi. Muammo A — murakkab state: ilovada ko'p bir-biriga bog'liq state va ularni o'zgartiradigan ko'p usul bo'lsa, alohida
useStatelar tarqoq va chalkash bo'ladi (qaysi o'zgarish qayerda?) —useReducerbarcha o'zgarish mantig'ini bitta reducer da markazlashtiradi (tartib, bashoratlilik). Muammo B — keraksiz qayta hisob/render: har render'da komponent funksiyasi boshidan ishlaydi (11.2: 2.2), shuning uchun qimmat hisob (masalan 1000 element saralash) qaytadan bajariladi, va yangi obyekt/funksiya yaratiladi (yangi havola memoizatsiyalangan bola keraksiz re-render bo'ladi — 11.5: 2.9) —useMemoqimmat hisob natijasini keshlaydi,useCallbackfunksiya havolasini barqaror ushlaydi. Asosiy farq:useReducer— tartib uchun (state mantig'ini tashkil qilish);useMemo/useCallback— tezlik uchun (keraksiz hisob va render'larni to'xtatish). Endi har birini chuqur ko'ramiz.
2.2. useReducer nima va nega (useState chegarasi)
useState QACHON YETMAYDI:
- ko'p bog'liq state (loading + data + error + page + filter...)
- keyingi state oldingisiga murakkab bog'liq (form wizard, savat)
- bir hodisa BIR NECHA state'ni o'zgartiradi (chalkash setX'lar)
useReducer G'OYASI — "state o'zgarishini MARKAZLASHTIRISH":
- barcha o'zgarish mantig'i BITTA funksiyada (reducer)
- komponent faqat "nima sodir bo'ldi" (action) ni JO'NATADI (dispatch)
- "qanday o'zgartirish" — reducer'ning ishi
┌──────────────────────────────────────────────────────────────┐
│ Komponent: dispatch({ type: "INCREMENT" }) "nima bo'ldi" │
│ │ │
│ ▼ │
│ Reducer: (state, action) => newState "qanday o'zgartirish" │
│ │ │
│ ▼ │
│ Yangi state re-render │
└──────────────────────────────────────────────────────────────┘
useReducer — Redux'ning komponent-ichi modeli (12.2 oson bo'ladi)
useReducer—useStatening kuchliroq muqobili, murakkab state mantig'i uchun.useStateqachon yetmaydi: ko'p bir-biriga bog'liq state bo'lganda (loading+data+error+page+filter), keyingi state oldingisiga murakkab bog'liq bo'lganda (form wizard, savat), yoki bitta hodisa bir nechta state'ni o'zgartirganda (tarqoqsetXlar — chalkash).useReducerg'oyasi — state o'zgarishini markazlashtirish: barcha o'zgarish mantig'i bitta funksiyada (reducer) yashaydi; komponent faqat "nima sodir bo'ldi" (action) nidispatchbilan jo'natadi, "qanday o'zgartirish" esa reducer'ning ishi. Bu — ma'lumot oqimini bashoratli qiladi: har o'zgarish bitta joydan o'tadi, sinash va kuzatish oson. Eng muhim bonus:useReducer— Reduxning 12.2-bob komponent ichidagi kichik modeli (bir xil(state, action) => newStateg'oyasi).useReducerni tushunsangiz, Redux sizga allaqachon tanish bo'ladi.
2.3. Reducer funksiya — pure, (state, action) => newState
REDUCER — eski state va action olib, YANGI state qaytaradigan SOF funksiya:
function reducer(state, action) {
switch (action.type) { // action turiga qarab
case "increment":
return { ...state, count: state.count + 1 }; // YANGI state (immutable — 11.4: 2.7)
case "decrement":
return { ...state, count: state.count - 1 };
case "set":
return { ...state, count: action.payload }; // payload — qo'shimcha ma'lumot
default:
return state; // noma'lum action — state o'zgarmaydi
}
}
QOIDALAR (reducer SOF funksiya bo'lishi shart):
Faqat state va action'dan YANGI state hisoblaydi (boshqa hech narsa)
Immutable — eski state'ni mutatsiya QILMAYDI (yangi obyekt — 11.4: 2.7)
Side effect YO'Q (fetch, taymer, Math.random, Date.now — reducer ichida emas!)
"Reducer" nomi — Array.reduce'dan (yig'ib boradi: (akkumulyator, element) => yangi akkumulyator)Reducer funksiya —
useReducerning yuragi: eski state va action olib, yangi state qaytaradigan sof funksiya —(state, action) => newState. Odatda ichidaswitch (action.type)bo'ladi: har action turiga qarab yangi state hisoblanadi. Har holatda yangi obyekt qaytariladi (immutable — eski state mutatsiya qilinmaydi — 11.4: 2.7), vadefaultholatda o'zgarmagan state qaytariladi (noma'lum action xavfsiz). Reducer qat'iy qoidalari: (1) sof bo'lishi shart — faqat state va action'dan yangi state hisoblaydi, boshqa hech narsa; (2) immutable — eski state'ni o'zgartirmaydi; (3) side effect yo'q — fetch, taymer,Math.random(),Date.now()reducer ichida bo'lmaydi (ulardispatchdan oldin yokiuseEffectda). "Reducer" nomiArray.reducedan keladi 2.7-bob: u ham(akkumulyator, element) => yangiAkkumulyatorshaklida qiymatni "yig'ib boradi" — bu yerda state akkumulyator, action element. Sof reducer — bashoratli, oson sinaladigan (bir xil kirish bir xil chiqish), Redux DevTools bilan kuzatiladigan kodning asosi.
2.4. dispatch va action — type va payload
DISPATCH — reducer'ga "nima bo'ldi"ni jo'natuvchi funksiya:
dispatch({ type: "increment" }); // oddiy action (faqat tur)
dispatch({ type: "add_todo", payload: "Yangi vazifa" }); // ma'lumotli action
ACTION — sodir bo'lgan hodisani tasvirlovchi OBYEKT:
{
type: "add_todo", // MAJBURIY — qanday o'zgarish (string)
payload: { ... } // IXTIYORIY — qo'shimcha ma'lumot (yangi element, id, ...)
}
KONVENSIYA:
- type — aniq, tushunarli nom ("add_todo", "REMOVE_ITEM", "set_filter")
- payload — o'zgarish uchun kerakli ma'lumot
KOMPONENTDA (toza — mantiq reducer'da):
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "set", payload: 100 })}>100 qil</button>
Komponent FAQAT dispatch qiladi (nima bo'ldi); QANDAY o'zgartirish — reducer'da (ajratilgan)
dispatchva action —useReducerning ikkinchi qismi.dispatch— reducer'ga **"nima bo'ldi"**ni jo'natuvchi funksiya (useReducerqaytaradi). Action — sodir bo'lgan hodisani tasvirlovchi obyekt:type(majburiy — qanday o'zgarish, string —"increment","add_todo") va ixtiyoriypayload(o'zgarish uchun kerakli ma'lumot — yangi element, id, filtr qiymati). Komponent shunchakidispatch({ type: "add_todo", payload: text })chaqiradi — va shu yerda kodning go'zalligi: komponent faqat "nima bo'ldi"ni aytadi (dispatch), "qanday o'zgartirish" esa reducer'ning ishi (ajratilgan mas'uliyat — 9.1 SRP). Bu — UI (komponent) va biznes mantiq (reducer) ni ajratadi: komponentlar toza qoladi (faqat dispatch), butun state mantig'i bitta sinaladigan joyda. Konvensiya:typeaniq va tushunarli nom bo'lsin;payload— standart nom (Redux'dan keladi). Bu naqsh keyinchalik Redux Toolkit'da deyarli bir xil ko'rinadi 12.2-bob — shuning uchun bu yerda yaxshi o'zlashtirsangiz, foydasi ikki barobar.
2.5. useReducer anatomiyasi va lazy init
const [state, dispatch] = useReducer(reducer, initialState);
// │ │ │ │
// │ │ │ └─ boshlang'ich state
// │ │ └─ reducer funksiya 2.3-bob
// │ └─ action jo'natuvchi 2.4-bob
// └─ joriy state
TO'LIQ MISOL:
const initialState = { count: 0 };
function reducer(state, action) { ... }
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
<p>{state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
</>
);
}
LAZY INIT (3-argument — boshlang'ich state'ni FUNKSIYA bilan hisoblash):
useReducer(reducer, initialArg, init); // init(initialArg) faqat 1-render'da
// masalan: localStorage'dan boshlang'ich o'qish (qimmat — bir marta)
useState'ga o'xshash: [qiymat, o'zgartiruvchi] — lekin o'zgartiruvchi DISPATCH (action orqali)
useReduceranatomiyasi — ikki argument oladi: reducer funksiya 2.3-bob va boshlang'ich state; va massiv qaytaradi:[state, dispatch](joriy state va action jo'natuvchi). TuzilishiuseStatega o'xshaydi ([qiymat, o'zgartiruvchi]), lekin o'zgartiruvchi —dispatch(to'g'ridan qiymat emas, action orqali). Lazy init (uchinchi, ixtiyoriy argument):useReducer(reducer, initialArg, init)— boshlang'ich state'niinit(initialArg)funksiyasi bilan hisoblaydi (faqat birinchi render'da — qimmat boshlang'ich hisob uchun, masalanlocalStoragedan o'qish — 11.5'dagi lazy initial state bilan bir xil g'oya). Foydalanish naqshi: reducer va initialState'ni komponentdan tashqarida (yuqorida) e'lon qilasiz (ular har render'da qayta yaralmasligi uchun), komponentda faqatuseReducer(reducer, initialState)chaqirasiz vadispatchbilan action jo'natasiz. Bu — toza, qayta ishlatiladigan struktura.
2.6. useState vs useReducer — qachon qaysi
┌──────────────────────────┬─────────────────┬─────────────────────┐
│ │ useState │ useReducer │
├──────────────────────────┼─────────────────┼─────────────────────┤
│ Oddiy, mustaqil state │ ideal │ ortiqcha │
│ Ko'p bog'liq state │ chalkash │ ideal │
│ Murakkab o'zgartirish │ tarqoq setX │ markazlashgan │
│ Keyingi state oldingiga │ qiyin │ reducer'da aniq │
│ bog'liq │ │ │
│ Sinash (test) │ qiyinroq │ oson (sof fn) │
│ Debug (kuzatish) │ tarqoq │ bitta joy │
└──────────────────────────┴─────────────────┴─────────────────────┘
AMALIY QOIDA:
- 1-2 oddiy state useState
- ko'p bog'liq state YOKI murakkab o'tishlar useReducer
- butun ilova bo'ylab Redux/Zustand (12.2, 12.5)
useState'dan boshla; murakkablashca useReducer'ga ko'ch (oldindan optimallashtirma)
useStatevsuseReducer— qaysi birini qachon.useState— oddiy, mustaqil state uchun ideal (count,isOpen, bitta input); ko'p bog'liq state bilan chalkash bo'ladi.useReducer— ko'p bir-biriga bog'liq state, murakkab o'zgartirishlar, keyingi state oldingisiga bog'liq bo'lganda ideal: barcha mantiq markazlashgan, oson sinaladi (reducer — sof funksiya, React'siz ham test qilinadi), oson kuzatiladi (har o'zgarish dispatch orqali — bitta joyda). Amaliy qoida: 1-2 oddiy stateuseState; ko'p bog'liq state yoki murakkab o'tishlar (wizard, savat, murakkab forma)useReducer; butun ilova bo'ylab ulashiladigan state Redux/Zustand (12.2, 12.5). Eng muhim maslahat: har doimuseStatedan boshla (sodda), va faqat murakkablik o'sgandauseReducerga ko'ch (oldindan, "ehtimol kerak bo'lar" deb optimallashtirma — 2.13). Ko'pinchauseReducerga o'tish belgisi — bir nechtasetXdoim birga chaqirilayotgani yoki state mantig'i komponentni "to'ldirib" yuborganidir.
2.7. Memoization nima — keshlash g'oyasi
MEMOIZATION — funksiya natijasini KESHLASH: bir xil kirish keshdan javob (qayta hisoblamaslik)
Oddiy g'oya (React'siz):
qiymat = qimmatHisob(a, b) // 1-marta: hisoblanadi (sekin)
qiymat = qimmatHisob(a, b) // a, b o'zgarmasa: keshdan (tez)
REACT'DA MUAMMO: har render'da komponent funksiyasi BOSHIDAN ishlaydi (11.2: 2.2)
function List({ items }) {
const sorted = items.slice().sort(...); // HAR render'da qaytadan saralanadi (10000 element — sekin!)
return ...;
}
YECHIM — useMemo: natijani keshla, dependency o'zgarmasa qayta hisoblama:
const sorted = useMemo(() => items.slice().sort(...), [items]); // items o'zgarmasa — kesh
Memoization "vaqtni xotiraga almashtirish" (kesh xotira oladi, lekin hisobni tejaydi)
Faqat QIMMAT hisob uchun (arzon hisobni keshlash — foydasiz, ba'zan zararli — 2.13)Memoization (keshlash) — funksiya natijasini saqlash: bir xil kirish (argument) bilan qayta chaqirilganda, qaytadan hisoblamasdan keshdan javob berish. React'dagi muammo: har render'da komponent funksiyasi boshidan ishlaydi (11.2: 2.2), shuning uchun ichidagi qimmat hisob (masalan 10000 element saralash) har render'da qaytadan bajariladi — garchi natija o'zgarmasa ham (sekin).
useMemobuni hal qiladi: hisob natijasini keshlaydi va faqat dependency o'zgarganda qayta hisoblaydi (useMemo(() => qimmatHisob(items), [items])—itemso'zgarmasa, kesh). Ikki muhim nuqta: (1) memoization — "vaqtni xotiraga almashtirish" savdosi (kesh xotira band qiladi, lekin takroriy hisobni tejaydi); (2) shuning uchun u faqat haqiqatan qimmat hisob uchun mantiqli — arzon hisobni (a + b, kichik massiv) keshlash foydasiz va ba'zan zararli (keshni saqlash/taqqoslash ham vaqt oladi — 2.13). Memoizatsiyaning ikkinchi, ko'pincha muhimroq vazifasi — referential equality 2.9-bob.
2.8. useMemo — qimmat hisobni keshlash
useMemo(() => qiymat, [deps]) — qiymatni keshlaydi, deps o'zgargandagina qayta hisoblaydi
const filteredSorted = useMemo(() => {
console.log("Hisoblanmoqda..."); // faqat deps o'zgarganda ko'rinadi
return items
.filter(item => item.active)
.sort((a, b) => a.price - b.price);
}, [items]); // items o'zgarmasa — keshdan (qayta hisob yo'q)
QACHON useMemo (haqiqatan kerak):
Qimmat hisob (katta massiv filter/sort/reduce, og'ir transformatsiya)
Referential equality kerak (obyekt/massivni barqaror ushlash — 2.9)
QACHON KERAK EMAS:
Arzon hisob (a + b, kichik massiv) — keshlash foydasiz 2.13-bob
Har render'da baribir o'zgaradigan deps — kesh hech qachon ishlamaydi
useMemo — KAFOLAT emas, OPTIMIZATSIYA maslahati (React keshni tashlashi mumkin)
Komponent xulq-atvori useMemo'siz ham BIR XIL bo'lishi kerak (faqat tezlik farqi)
useMemo— qimmat hisob natijasini keshlaydigan hook:useMemo(() => qiymat, [deps])— funksiyani faqat deps o'zgarganda qayta chaqiradi, aks holda oldingi natijani (keshni) qaytaradi. Misol: katta massivni filter + sort qilish —itemso'zgarmasa, qaytadan hisoblanmaydi. QachonuseMemokerak: (1) haqiqatan qimmat hisob (katta massivfilter/sort/reduce, og'ir transformatsiya); (2) referential equality kerak bo'lganda — obyekt/massiv havolasini barqaror ushlash (2.9 — bu ko'pincha asosiy sabab). Qachon kerak emas: arzon hisob (a + b, kichik massiv — keshlash foydasiz); yoki har render'da baribir o'zgaradigan deps (kesh hech qachon ishlamaydi — bekorga). Ikki nozik haqiqat: (1)useMemo— kafolat emas, optimizatsiya maslahati: React ba'zan keshni tashlab, qayta hisoblashi mumkin (xotira siqilganda), shuning uchun unga mantiqiy to'g'rilik uchun tayanma (faqat tezlik); (2) komponentuseMemosiz ham bir xil ishlashi kerak —useMemofaqat tezlikni o'zgartiradi, natijani emas. AgaruseMemoni olib tashlaganda kod buzilsa — demak uni noto'g'ri ishlatilgan.
2.9. Referential equality — obyekt/massiv havolasini barqaror ushlash
REFERENTIAL EQUALITY (havola tengligi) — React obyekt/funksiyani === bilan solishtiradi:
{} === {} // false! (har obyekt — yangi havola, garchi ichi bir xil)
[1,2] === [1,2] // false!
const fn = () => {}; fn === fn // true (AYNI havola)
MUAMMO — har render'da yangi obyekt/funksiya yaratiladi (yangi havola):
function Parent() {
const config = { theme: "dark" }; // HAR render'da YANGI obyekt
return <Child config={config} />; // Child har doim "yangi prop" ko'radi re-render
}
// Yoki useEffect deps'da object cheksiz effekt (11.5: 2.9)
YECHIM — useMemo bilan havolani BARQAROR ushlash:
const config = useMemo(() => ({ theme: "dark" }), []); // bir xil havola (deps o'zgarmaganda)
// Child bir xil prop ko'radi re-render YO'Q; useEffect deps barqaror tsikl yo'q
┌────────────────────────────────────────────────────────────┐
│ Primitiv (number/string/bool): qiymat bo'yicha === (oson) │
│ Obyekt/massiv/funksiya: HAVOLA bo'yicha === (har yangi=farq)│
└────────────────────────────────────────────────────────────┘
Bu — React'ning eng nozik tushunchasi; memo/effect deps shunga tayanadiReferential equality (havola tengligi) — React'ning eng nozik, lekin eng muhim tushunchalaridan biri. React obyekt, massiv va funksiyalarni havola (reference) bo'yicha
===bilan solishtiradi:{} === {}false (ikki alohida obyekt, ichi bir xil bo'lsa ham, havolasi har xil); funksiya ham shunday. Muammo: komponent ichida yaratilgan obyekt/funksiya har render'da yangi havola oladi — shuning uchun unipropssifatida bolaga uzatsangiz, bola har doim "yangi prop" ko'radi (memoizatsiyalangan bola ham keraksiz re-render bo'ladi — 2.12), yokiuseEffectdeps'iga qo'ysangiz cheksiz effekt (11.5: 2.9). Yechim —useMemo(obyekt/massiv uchun) yokiuseCallback(funksiya uchun — 2.10) bilan havolani barqaror ushlash: deps o'zgarmasa, bir xil havola qaytariladi bola bir xil prop ko'radi (re-render yo'q), effekt deps barqaror (tsikl yo'q). Asosiy farqni yodda tut: primitiv qiymatlar (number, string, boolean) qiymat bo'yicha solishtiriladi (oson, muammosiz); obyekt/massiv/funksiya havola bo'yicha (har yangi = farq). Memoizatsiyaning eng muhim ishlatilishi — aynan shu referential barqarorlik, qimmat hisob emas.
2.10. useCallback — funksiyani keshlash
useCallback(fn, [deps]) — FUNKSIYA havolasini keshlaydi (deps o'zgarmaganda bir xil havola)
Har render'da yangi funksiya (yangi havola — 2.9):
function Parent() {
const handleClick = () => console.log("bosildi"); // HAR render'da YANGI havola
return <MemoChild onClick={handleClick} />; // MemoChild re-render (prop "o'zgardi")
}
useCallback bilan barqaror havola:
const handleClick = useCallback(() => console.log("bosildi"), []); // bir xil havola
// MemoChild bir xil onClick ko'radi re-render YO'Q 2.12-bob
useCallback === useMemo (funksiya uchun):
useCallback(fn, deps) === useMemo(() => fn, deps)
// useCallback funksiyaNING O'ZINI keshlaydi; useMemo funksiya NATIJASINI
QACHON useCallback:
Funksiyani React.memo'li bolaga prop sifatida uzatsang 2.12-bob
Funksiya useEffect/useMemo deps'da bo'lsa (barqaror dep — 11.5: 2.9)
Funksiya custom hook'dan qaytsa (qayta ishlatiladigan barqaror funksiya)
Oddiy funksiyani (memo'siz bolaga, deps'siz) useCallback'ga o'rama — foydasiz (2.13)
useCallback— funksiya havolasini keshlaydigan hook:useCallback(fn, [deps])— deps o'zgarmaganda bir xil funksiya havolasini qaytaradi (yangi yaratmaydi). 2.9 dagi muammoni hal qiladi: komponent ichidagi funksiya har render'da yangi havola oladi, shuning uchun uniReact.memo'li bolaga uzatsangiz, bola keraksiz re-render bo'ladi —useCallbackhavolani barqaror ushlaydi (bola bir xil prop ko'radi re-render yo'q). Munosabati:useCallback(fn, deps)aynanuseMemo(() => fn, deps)ga teng —useCallbackfunksiyaning o'zini keshlaydi,useMemoesa funksiya natijasini. QachonuseCallbackkerak: (1) funksiyaniReact.memo'li bolaga prop sifatida uzatganda 2.12-bob; (2) funksiyauseEffect/useMemodeps'ida bo'lganda (barqaror dep — 11.5: 2.9 tuzog'ini hal qiladi); (3) funksiya custom hook'dan qaytarilganda (qayta ishlatiladigan barqaror funksiya — 11.7). Lekin oddiy funksiyani (memo'siz bolaga beriladigan, deps'da bo'lmaganonClick)useCallbackga o'rash foydasiz — u faqat kodni murakkablashtiradi 2.13-bob.useCallbackfaqat referential barqarorlik haqiqatan kerak bo'lganda mantiqli.
2.11. useMemo vs useCallback — farq va o'xshashlik
┌──────────────┬────────────────────────────┬──────────────────────────┐
│ │ useMemo │ useCallback │
├──────────────┼────────────────────────────┼──────────────────────────┤
│ Keshlaydi │ QIYMAT (hisob natijasi) │ FUNKSIYANI (havola) │
│ Sintaksis │ useMemo(() => hisob, deps) │ useCallback(fn, deps) │
│ Qaytaradi │ hisob natijasi │ funksiyaning o'zi │
│ Asosiy maqsad│ qimmat hisob + obyekt barqaror│ funksiya havolasi barqaror│
└──────────────┴────────────────────────────┴──────────────────────────┘
TENGLIK: useCallback(fn, deps) ≡ useMemo(() => fn, deps)
const sorted = useMemo(() => items.sort(...), [items]); // NATIJA (massiv)
const onAdd = useCallback((x) => dispatch({type:"add", payload:x}), []); // FUNKSIYA
useMemo — "natijani keshla"; useCallback — "funksiyani keshla"
Ikkalasi ham referential barqarorlik 2.9-bob uchun; faqat nima keshlanishi farq qiladi
useMemovsuseCallback— bir xil g'oyaning (memoizatsiya) ikki ko'rinishi, faqat nima keshlanishi bilan farq qiladi.useMemo— qiymatni (hisob natijasini) keshlaydi:useMemo(() => hisob(a, b), [a, b])hisob natijasini qaytaradi.useCallback— funksiyani (uning havolasini) keshlaydi:useCallback(fn, [deps])funksiyaning o'zini qaytaradi. Ular matematik jihatdan bog'liq:useCallback(fn, deps)≡useMemo(() => fn, deps)(useCallback — funksiyani qaytaradigan useMemo). Misol:const sorted = useMemo(() => items.sort(...), [items])— natija (saralangan massiv);const onAdd = useCallback(x => dispatch(...), [])— funksiya. Ikkalasining ham asosiy maqsadi — referential barqarorlik 2.9-bob: obyekt/massiv havolasini barqaror ushlash uchunuseMemo, funksiya havolasini barqaror ushlash uchunuseCallback. Eslab qolish oson:useMemo— "natijani keshla",useCallback— "funksiyani keshla". Ikkalasi ham faqat bu barqarorlik (yoki qimmat hisob) haqiqatan kerak bo'lganda ishlatiladi.
2.12. React.memo bilan bog'lanish (props o'zgarmasa render qilmaslik)
RE-RENDER QOIDASI: ota render bo'lsa, BARCHA bolalari ham re-render (11.2: 2.2)
ba'zan bola props'i O'ZGARMAGAN bo'lsa ham bekorga render bo'ladi
React.memo — bola props'i O'ZGARMASA, uni RE-RENDER QILMASLIK (keshlangan natija):
const Child = React.memo(function Child({ name }) {
console.log("Child render");
return <p>{name}</p>;
});
// name o'zgarmasa, ota render bo'lsa ham Child render BO'LMAYDI
LEKIN — React.memo props'ni === bilan solishtiradi 2.9-bob:
obyekt/funksiya prop HAR render'da yangi havola memo "o'zgardi" deb o'ylaydi BEKORGA render
SHUNING UCHUN useMemo (obyekt prop) + useCallback (funksiya prop) memo bilan BIRGA ishlatiladi:
const config = useMemo(() => ({...}), []); // barqaror obyekt
const onClick = useCallback(() => {...}, []); // barqaror funksiya
<MemoChild config={config} onClick={onClick} />; // endi memo HAQIQATAN ishlaydi
React.memo + useMemo + useCallback — UCHALASI BIRGA ishlaydi (biri yolg'iz ko'pincha foydasiz)
React.memo— komponentni o'rab, props o'zgarmasa uni re-render qilmaydigan yuqori tartibli komponent (HOC). Eslatma: odatda ota render bo'lganda barcha bolalari ham re-render bo'ladi (11.2: 2.2) — garchi bola props'i o'zgarmagan bo'lsa ham (bu ko'pincha tezlik uchun muammo emas, lekin qimmat bola uchun isrof).React.memo(Child)— bola props'ini oldingi bilan solishtiradi va o'zgarmagan bo'lsa render qilmaydi (keshlangan natijani ishlatadi). Lekin muhim tuzoq:React.memoprops'ni===bilan solishtiradi 2.9-bob — agar obyekt yoki funksiya prop uzatsangiz, u har render'da yangi havola oladi, shuning uchunmemo"props o'zgardi" deb o'ylaydi va baribir render qiladi (memo foydasiz bo'lib qoladi). Yechim: obyekt prop'larniuseMemobilan, funksiya prop'larniuseCallbackbilan barqaror ushlash — shundaginaReact.memohaqiqatan ishlaydi. DemakReact.memo+useMemo+useCallbackuchalasi birga ishlaydi: biri yolg'iz ko'pincha foydasiz (memo'siz callback foydasiz, callback'siz memo foydasiz). Bu uchlik — React performance optimizatsiyasining 11.11-bob yadrosi.
2.13. Qachon optimallashtirMAslik (premature optimization)
ENG KENG XATO: useMemo/useCallback'ni HAMMA joyga tiqishtirish ("tezroq bo'lar")
HAQIQAT:
- Memoizatsiya BEPUL emas — kesh xotira oladi, deps har render'da solishtiriladi
- Arzon hisob/oddiy funksiya uchun — memoizatsiya ZARARLI (foydadan ko'p xarajat)
- Kod murakkablashadi (o'qish/saqlash qiyinlashadi)
TO'G'RI YONDASHUV (3 qadam):
1. AVVAL ODDIY yoz (memoizatsiyasiz)
2. MUAMMO bormi? — O'LCHA (React DevTools Profiler — 11.11), sezsang
3. FAQAT o'sha qimmat joyni memoizatsiya qil (maqsadli, dalilga asoslangan)
QACHON memoizatsiya OQLANADI:
React.memo'li bolaga obyekt/funksiya prop 2.12-bob
Haqiqatan qimmat hisob (profiler ko'rsatdi)
useEffect deps barqarorligi kerak (11.5: 2.9)
"Premature optimization is the root of all evil" — avval to'g'ri, keyin (kerak bo'lsa) tez
O'lchamasdan optimallashtirma (taxminga emas, dalilga asoslan)Qachon optimallashtirMAslik — bu bobning eng muhim amaliy darsi. Eng keng xato —
useMemo/useCallbackni "tezroq bo'lar" deb hamma joyga ishlatish. Haqiqat: memoizatsiya bepul emas — kesh xotira oladi, deps har render'da solishtiriladi, va kod murakkablashadi (o'qish/saqlash qiyinlashadi). Arzon hisob yoki oddiy funksiya uchun memoizatsiya zararli (foydadan ko'ra xarajati ko'p). To'g'ri yondashuv (3 qadam): (1) avval oddiy yoz (memoizatsiyasiz); (2) muammo bormi? — o'lcha (React DevTools Profiler bilan — 11.11), sekinlikni sezsangiz; (3) faqat o'sha aniq qimmat joyni memoizatsiya qil (maqsadli, dalilga asoslangan). Memoizatsiya qachon oqlanadi:React.memo'li bolaga obyekt/funksiya prop 2.12-bob; haqiqatan qimmat hisob (profiler tasdiqlagan);useEffectdeps barqarorligi (11.5: 2.9). Mashhur tamoyil: "premature optimization is the root of all evil" — avval to'g'ri kod yoz, keyin (agar kerak bo'lsa, o'lchovga asoslanib) tezlashtir. Taxminga emas, dalilga asoslan. Bu — junior'ni senior'dan ajratadigan eng aniq tafakkur farqi.
2.14. React Compiler — avto-memoizatsiya (kelajak konteksti)
REACT COMPILER (2024-2025, React 19 bilan) — memoizatsiyani AVTOMATIK qiladi:
Eski qo'lda: Compiler bilan:
const x = useMemo(() => f(a), [a]); const x = f(a); // compiler O'ZI optimallashtiradi
const fn = useCallback(() => {}, []); const fn = () => {};
Compiler kodingni TAHLIL qilib, qayerda memoizatsiya kerakligini O'ZI aniqlaydi
useMemo/useCallback'ni QO'LDA yozish ko'p holda KERAK BO'LMAYDI
HOZIRGI HOLAT (2026):
- React Compiler barqaror (stable) — yangi loyihalarda tavsiya etiladi
- LEKIN tushunish SHART: compiler "sehr" emas — u shu bobdagi qoidalarga tayanadi
(sof komponent, Rules of Hooks, immutability — buzilsa compiler ham yordam berolmaydi)
Compiler bo'lsa ham — bu bobni BIL: nima bo'layotganini tushunish (debug, eski kod, nazorat)
Yangi loyiha: compiler'ga ishon; lekin referential equality 2.9-bob tushunchasi BARIBIR kerakReact Compiler — 2024-2025'da chiqqan, React 19 bilan keluvchi vosita: u memoizatsiyani avtomatik qiladi. Ya'ni siz
useMemo/useCallbackni qo'lda yozish o'rniga, kompilyator kodni tahlil qilib, qayerda memoizatsiya kerakligini o'zi aniqlaydi va qo'shadi (const x = f(a)ni avtomatikuseMemolangan qiladi). Bu — ko'p holda qo'lda memoizatsiya yozish zaruratini yo'qotadi (kod soddapoq, lekin baribir optimal). Hozirgi holat (2026): React Compiler barqaror va yangi loyihalarda tavsiya etiladi. Lekin ikki muhim ogohlantirish: (1) compiler "sehr" emas — u aynan shu bobdagi (va 11.2, 11.4) qoidalarga tayanadi: sof komponent, Rules of Hooks (11.5: 2.2), immutability (11.4: 2.7); bu qoidalarni buzsangiz, compiler ham yordam berolmaydi (shuning uchun ularni bilish shart); (2) bu hooklarni tushunish baribir kerak — eski kodni o'qish, xato tuzatish (debug), va aniq nazorat kerak bo'lganda. Demak: yangi loyihada compiler'ga ishonsangiz bo'ladi, lekin referential equality 2.9-bob va memoizatsiya tushunchasi — har doim zarur. Compiler — vosita, bilim emas.
3. Sintaksis — tez ma'lumotnoma
REDUCER 2.3-bob: function reducer(state, action) { switch(action.type){...} return newState }
useReducer 2.5-bob: const [state, dispatch] = useReducer(reducer, initialState)
DISPATCH 2.4-bob: dispatch({ type: "add", payload: data })
useMemo 2.8-bob: const x = useMemo(() => qimmatHisob(a, b), [a, b])
useMemo OBYEKT2.9-bob:const cfg = useMemo(() => ({ a, b }), [a, b]) // barqaror havola
useCallback(2.10): const fn = useCallback(() => {...}, [deps])
React.memo 2.12-bob: const C = React.memo(function C(props){...})
TENGLIK 2.11-bob: useCallback(fn, deps) ≡ useMemo(() => fn, deps)
QOIDA 2.13-bob: avval o'lcha (Profiler) keyin memoizatsiya (taxminga emas)4. Batafsil kod namunalari
Misol 1 — useReducer: oddiy hisoblagich (2.3, 2.4, 2.5)
import { useReducer } from "react";
// Reducer — komponentdan TASHQARIDA (har render'da qayta yaralmasligi uchun)
function counterReducer(state, action) {
switch (action.type) {
case "increment": return { count: state.count + 1 };
case "decrement": return { count: state.count - 1 };
case "reset": return { count: 0 };
default: return state; // noma'lum action — o'zgarmaydi
}
}
function Counter() {
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
return (
<div>
<p>{state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
</div>
);
}
// Komponent FAQAT dispatch qiladi; barcha mantiq reducer'da (ajratilgan — 2.4)Misol 2 — useReducer: action payload bilan (todo — 2.4)
function todoReducer(state, action) {
switch (action.type) {
case "add":
return [...state, { id: crypto.randomUUID(), text: action.payload, done: false }];
case "toggle":
return state.map(t => t.id === action.payload ? { ...t, done: !t.done } : t);
case "remove":
return state.filter(t => t.id !== action.payload);
case "clear_done":
return state.filter(t => !t.done);
default:
return state;
}
}
function TodoApp() {
const [todos, dispatch] = useReducer(todoReducer, []);
const [input, setInput] = useState("");
return (
<div>
<input value={input} onChange={e => setInput(e.target.value)} />
<button onClick={() => { dispatch({ type: "add", payload: input }); setInput(""); }}>
Qo'shish
</button>
<ul>
{todos.map(t => (
<li key={t.id}>
<span onClick={() => dispatch({ type: "toggle", payload: t.id })}
style={{ textDecoration: t.done ? "line-through" : "none" }}>{t.text}</span>
<button onClick={() => dispatch({ type: "remove", payload: t.id })}></button>
</li>
))}
</ul>
<button onClick={() => dispatch({ type: "clear_done" })}>Bajarilganlarni tozala</button>
</div>
);
}
// 11.4 da useState bilan qilgan todo'ni solishtir: bu yerda mantiq BITTA reducer'da (toza, sinaladigan)Misol 3 — useReducer: murakkab forma (bog'liq state — 2.6)
const initial = { values: { email: "", password: "" }, errors: {}, submitting: false };
function formReducer(state, action) {
switch (action.type) {
case "field":
return { ...state, values: { ...state.values, [action.name]: action.value } };
case "errors":
return { ...state, errors: action.payload };
case "submit_start":
return { ...state, submitting: true, errors: {} };
case "submit_end":
return { ...state, submitting: false };
default:
return state;
}
}
function LoginForm() {
const [state, dispatch] = useReducer(formReducer, initial);
const { values, errors, submitting } = state;
function handleChange(e) {
dispatch({ type: "field", name: e.target.name, value: e.target.value });
}
return (
<form>
<input name="email" value={values.email} onChange={handleChange} />
{errors.email && <small className="error">{errors.email}</small>}
<input name="password" type="password" value={values.password} onChange={handleChange} />
<button disabled={submitting}>{submitting ? "Yuborilmoqda..." : "Kirish"}</button>
</form>
);
}
// Ko'p bog'liq state (values+errors+submitting) — useReducer bilan TARTIBLI (useState bo'lca tarqoq)Misol 4 — useReducer: lazy init (localStorage'dan — 2.5)
function init(initialTodos) {
const saved = localStorage.getItem("todos"); // qimmat — faqat 1 marta (lazy)
return saved ? JSON.parse(saved) : initialTodos;
}
function TodoApp() {
// 3-argument: init funksiya boshlang'ich state'ni hisoblaydi (faqat mount'da)
const [todos, dispatch] = useReducer(todoReducer, [], init);
// ...
}
// init(initialArg) — faqat birinchi render'da (localStorage o'qishni har render takrorlamaydi)Misol 5 — useMemo: qimmat hisob (2.8)
function ProductStats({ products }) {
// Qimmat hisob (katta massiv reduce) — har render'da emas, faqat products o'zgapganda
const stats = useMemo(() => {
console.log("Statistika hisoblanmoqda..."); // faqat products o'zgapganda ko'rinadi
return {
total: products.length,
avgPrice: products.reduce((s, p) => s + p.price, 0) / products.length,
maxPrice: Math.max(...products.map(p => p.price)),
};
}, [products]); // products o'zgapmasa — keshdan
return <div>Jami: {stats.total}, O'rtacha: {stats.avgPrice.toFixed(0)}</div>;
}Misol 6 — useMemo: referential equality (effekt tuzog'i yechimi — 2.9)
function Chart({ rawData }) {
// const options = { color: "blue", points: rawData }; // har render'da yangi havola
// useEffect(() => { drawChart(options); }, [options]); // cheksiz/har render effekt (11.5: 2.9)
// useMemo — options havolasi barqaror (rawData o'zgapmasa bir xil obyekt)
const options = useMemo(() => ({
color: "blue",
points: rawData,
}), [rawData]);
useEffect(() => {
drawChart(options); // endi options barqaror effekt faqat kerak bo'lganda
}, [options]); // rawData o'zgapgandagina qayta chizadi
return <canvas id="chart" />;
}
// useMemo bu yerda HISOB uchun emas, HAVOLA BARQARORLIGI uchun 2.9-bob — asosiy ishlatilishMisol 7 — useMemo: filtrlangan ro'yxat (oqlangan holat — 2.8)
function SearchableList({ items, query }) {
// Katta ro'yxat (10000+) filter — query yoki items o'zgapgandagina qayta hisobla
const filtered = useMemo(() => {
return items.filter(item =>
item.name.toLowerCase().includes(query.toLowerCase())
);
}, [items, query]); // ikkala dep ham kerak (exhaustive — 11.5: 2.6)
return <ul>{filtered.map(i => <li key={i.id}>{i.name}</li>)}</ul>;
}
// Kichik ro'yxat (10-100) bo'lca — useMemo KERAK EMAS (arzon hisob — 2.13). Faqat KATTA da.Misol 8 — useCallback + React.memo (bola re-renderini to'xtatish — 2.10, 2.12)
// Memoizatsiyalangan bola — props o'zgapmasa render bo'lmaydi
const ExpensiveChild = React.memo(function ExpensiveChild({ onAction, label }) {
console.log("ExpensiveChild render:", label);
return <button onClick={onAction}>{label}</button>;
});
function Parent() {
const [count, setCount] = useState(0);
const [other, setOther] = useState(0);
// const handleAction = () => console.log("action"); // har render yangi memo foydasiz
// useCallback — barqaror havola ExpensiveChild "other" o'zgapganda render BO'LMAYDI
const handleAction = useCallback(() => {
console.log("action bajarildi");
}, []); // bo'sh deps har doim bir xil funksiya
return (
<div>
<p>Count: {count}, Other: {other}</p>
<button onClick={() => setOther(o => o + 1)}>Other +1</button> {/* bu ExpensiveChild'ni render qilmasin */}
<ExpensiveChild onAction={handleAction} label="Bajarish" />
</div>
);
}
// useCallback'siz: "Other +1" bossang ExpensiveChild ham render bo'lardi (yangi onAction havolasi)
// useCallback bilan: ExpensiveChild render BO'LMAYDI (onAction bir xil — memo ishlaydi — 2.12)Misol 9 — useCallback effekt deps'da (barqaror dependency — 2.10)
function SearchResults({ endpoint }) {
const [results, setResults] = useState([]);
// Funksiya barqaror bo'lsin (effekt deps'da ishlatamiz — 11.5: 2.9)
const fetchResults = useCallback(async () => {
const res = await fetch(endpoint);
setResults(await res.json());
}, [endpoint]); // endpoint o'zgapgandagina yangi funksiya
useEffect(() => {
fetchResults(); // fetchResults barqaror effekt faqat endpoint o'zgapganda
}, [fetchResults]); // funksiya dep (barqaror — tsikl yo'q)
return <ul>{results.map(r => <li key={r.id}>{r.title}</li>)}</ul>;
}
// useCallback'siz: fetchResults har render yangi useEffect har render ishlardi (tsikl xavfi)Misol 10 — Anti-pattern: hammani memoizatsiya qilish (XATO — 2.13)
function BadExample({ a, b }) {
// KERAKSIZ memoizatsiya (arzon hisob — keshlash foydadan zararli):
const sum = useMemo(() => a + b, [a, b]); // a + b — arzon, useMemo ortiqcha
const greeting = useMemo(() => "Salom", []); // konstanta — memoizatsiya kulgili
const handleClick = useCallback(() => alert(a), [a]); // memo'siz bolaga — foydasiz
return <button onClick={handleClick}>{greeting}: {sum}</button>;
}
// TO'G'RI — oddiy yoz (memoizatsiyasiz):
function GoodExample({ a, b }) {
const sum = a + b; // arzon — to'g'ridan hisobla
const handleClick = () => alert(a); // oddiy funksiya — o'rash shart emas
return <button onClick={handleClick}>Salom: {sum}</button>;
}
// Memoizatsiya — DALILGA asoslangan optimizatsiya (profiler), "har ehtimolga qarshi" emas (2.13)Misol 11 — useReducer + Context (global state naqshi — 2.2)
// useReducer'ni Context bilan birlashtirib, kichik "store" yaratish (Redux'siz)
const CartContext = createContext();
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;
}
}
export function CartProvider({ children }) {
const [cart, dispatch] = useReducer(cartReducer, []);
return (
<CartContext.Provider value={{ cart, dispatch }}>
{children}
</CartContext.Provider>
);
}
export const useCart = () => useContext(CartContext);
// Istalgan komponentda:
function AddButton({ product }) {
const { dispatch } = useCart();
return <button onClick={() => dispatch({ type: "add", payload: product })}>Savatga</button>;
}
// useReducer + Context = oddiy global store (kichik ilova uchun Redux o'rniga — 12.1, 12.2)Misol 12 — To'liq: ma'lumotlar jadvali (useReducer + useMemo + useCallback)
const initial = { search: "", sortBy: "name", page: 1 };
function tableReducer(state, action) {
switch (action.type) {
case "search": return { ...state, search: action.payload, page: 1 }; // qidiruvda 1-sahifaga
case "sort": return { ...state, sortBy: action.payload };
case "page": return { ...state, page: action.payload };
default: return state;
}
}
function DataTable({ data }) { // data — katta massiv
const [state, dispatch] = useReducer(tableReducer, initial);
const { search, sortBy, page } = state;
// Qimmat: filter + sort (katta data) — faqat kerakli deps o'zgapganda (2.8)
const processed = useMemo(() => {
return data
.filter(row => row.name.toLowerCase().includes(search.toLowerCase()))
.sort((a, b) => (sortBy === "price" ? a.price - b.price : a.name.localeCompare(b.name)));
}, [data, search, sortBy]);
// Sahifalangan bo'lak (processed yoki page o'zgapganda)
const pageData = useMemo(() => processed.slice((page - 1) * 10, page * 10), [processed, page]);
// Barqaror handlerlar (agar memo'li satr komponentiga uzatilca — 2.10)
const onSearch = useCallback(e => dispatch({ type: "search", payload: e.target.value }), []);
return (
<div>
<input value={search} onChange={onSearch} placeholder="Qidirish" />
<button onClick={() => dispatch({ type: "sort", payload: "price" })}>Narx bo'yicha</button>
<ul>{pageData.map(row => <li key={row.id}>{row.name} — {row.price}</li>)}</ul>
<button onClick={() => dispatch({ type: "page", payload: page - 1 })} disabled={page === 1}>
Oldingi
</button>
</div>
);
}
// useReducer (murakkab state) + useMemo (qimmat hisob) + useCallback (barqaror handler) — birgaMisol 13 — React.memo + useMemo + useCallback uchligi (2.12)
const ProductCard = React.memo(function ProductCard({ product, onAddToCart }) {
console.log("ProductCard render:", product.name);
return (
<div className="card">
<h3>{product.name}</h3>
<button onClick={() => onAddToCart(product.id)}>Savatga</button>
</div>
);
});
function Catalog({ products }) {
const [cart, setCart] = useState([]);
const [filter, setFilter] = useState("");
// Barqaror funksiya (memo'li ProductCard uchun — 2.10, 2.12)
const handleAddToCart = useCallback((id) => {
setCart(prev => [...prev, id]); // updater — prev'ga tayanmaydi (11.4: 2.6)
}, []); // bo'sh deps barqaror
// Barqaror filtrlangan massiv (2.8)
const visible = useMemo(
() => products.filter(p => p.name.includes(filter)),
[products, filter]
);
return (
<div>
<input value={filter} onChange={e => setFilter(e.target.value)} />
{visible.map(p => (
<ProductCard key={p.id} product={p} onAddToCart={handleAddToCart} /> {/* memo ishlaydi */}
))}
<p>Savatda: {cart.length}</p>
</div>
);
}
// filter yozsang — faqat o'zgapgan kartalar render bo'ladi (handleAddToCart barqaror — memo ishlaydi)
// useCallback yoki React.memo bittasi yetishmasa — hammasi bekorga render bo'lardi (2.12)Misol 14 — O'lchash: optimallashtirishdan oldin (2.13)
// React DevTools Profiler bilan o'lcha 11.11-bob — qaysi komponent qancha render bo'ladi/vaqt oladi
// AVVAL oddiy yoz:
function List({ items }) {
const sorted = items.slice().sort((a, b) => a.value - b.value); // memoizatsiyasiz
return <ul>{sorted.map(i => <li key={i.id}>{i.label}</li>)}</ul>;
}
// Profiler ko'rsatdi: sort 50ms oladi, har render takrorlanadi (items kam o'zgapadi) ENDI memoizatsiya:
function ListOptimized({ items }) {
const sorted = useMemo(() => items.slice().sort((a, b) => a.value - b.value), [items]);
return <ul>{sorted.map(i => <li key={i.id}>{i.label}</li>)}</ul>;
}
// Tartib: 1) oddiy yoz 2) o'lcha (profiler) 3) faqat qimmat joyni optimallashtir (dalilga — 2.13)5. To'g'ri va noto'g'ri holatlar
1) Reducer ichida
reducer ichida fetch/Math.random/state mutatsiya (sof emas — 2.3)
reducer sof: faqat (state, action) => yangi state (immutable)2) useState vs useReducer
5+ bog'liq useState, tarqoq setX'lar (chalkash)
murakkab bog'liq state useReducer (markazlashgan — 2.6)3) useMemo — referential equality
const opt={...}; <Memo opt={opt}/> (har render yangi havola memo foydasiz — 2.9)
const opt=useMemo(()=>({...}),[deps]) (barqaror havola)4) useCallback + memo
React.memo'li bolaga oddiy funksiya (har render yangi memo ishlamaydi — 2.12)
useCallback bilan barqaror funksiya (memo haqiqatan ishlaydi)5) Ortiqcha memoizatsiya
useMemo(() => a+b, [a,b]) (arzon hisob — ortiqcha — 2.13)
const sum = a + b (oddiy; memoizatsiya faqat qimmat/referential uchun)6) Memoizatsiyaga mantiqiy tayanish
useMemo natijasiga to'g'rilik uchun tayanish (React keshni tashlashi mumkin — 2.8)
useMemo faqat TEZLIK; kod usiz ham bir xil ishlasin6. Keng tarqalgan xatolar va yechimlari
Xato 1 — Reducer state'ni o'zgartirmayapti
Sababi: reducer eski state'ni mutatsiya qildi (state.count++) yoki yangi obyekt qaytarmadi 2.3-bob. Yechimi: har doim yangi obyekt/massiv qaytar ({...state, ...}, [...state] — 11.4: 2.7).
Xato 2 — dispatch is not a function / action ishlamaydi
Sababi: useReducer qaytarganini noto'g'ri destructuring (const [dispatch, state] — tartib teskari). Yechimi: const [state, dispatch] = useReducer(...) (tartib: state, keyin dispatch — 2.5).
Xato 3 — React.memo ishlamayapti (bola baribir render bo'ladi)
Sababi: obyekt/funksiya prop har render yangi havola (2.9, 2.12). Yechimi: obyekt prop'ni useMemo, funksiya prop'ni useCallback bilan barqaror ush (Misol 8, 13).
Xato 4 — useMemo/useCallback qo'shdim, lekin tezroq bo'lmadi (yoki sekinroq)
Sababi: arzon hisob/oddiy funksiyani memoizatsiya qildingiz (xarajat foydadan ko'p — 2.13). Yechimi: olib tashla; faqat profiler ko'rsatgan qimmat joyni memoizatsiya qil (Misol 14).
Xato 5 — useMemo deps har render o'zgaradi (kesh hech qachon ishlamaydi)
Sababi: deps'da har render yangi yaraladigan obyekt/massiv/funksiya. Yechimi: deps'da primitiv qiymat ishlat yoki o'sha dep'ni ham memoizatsiya qil 2.9-bob.
Xato 6 — Reducer juda katta/chalkash bo'lib ketdi
Sababi: bitta reducerda juda ko'p mantiq. Yechimi: action'larni mantiqan bo'l; yordamchi funksiyalarga ajrat; juda katta bo'lsa — Redux Toolkit (slice'lar — 12.2).
Xato 7 — Stale closure useCallback ichida
Sababi: useCallbackning deps'i eskirgan (kerakli qiymat deps'da yo'q — 11.5: 2.9). Yechimi: kerakli qiymatni deps'ga qo'sh, yoki updater funksiya ishlat (setX(prev => ...) — 11.4: 2.6).
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- State 11.4-bob:
useReducer—useStatening murakkab muqobili; immutability bir xil 2.3-bob. - Hooks 11.5-bob:
useMemo/useCallbackobject-dependency tuzog'ini (11.5: 2.9) hal qiladi. - Performance 11.11-bob:
React.memo+useMemo+useCallback— optimizatsiya yadrosi 2.12-bob; profiler bilan o'lchash 2.13-bob. - Custom hooks 11.7-bob: custom hookdan barqaror funksiya qaytarish (
useCallback). - Context 12.1-bob:
useReducer+ Context = kichik global store (Misol 11). - Redux Toolkit 12.2-bob: reducer/action/dispatch — bir xil g'oya (2.2, 2.4);
useReducer— uning modeli. - React Compiler 2.14-bob: bu hooklarni avtomatlashtiradi, lekin qoidalar (sof, immutable) baribir kerak.
8. Eng yaxshi amaliyotlar (best practices)
useStatedan boshla (murakkablashsauseReducerga ko'ch — oldindan emas — 2.6).- Reducer — sof va immutable (side effect yo'q, yangi state — 2.3).
- Reducer/initialState komponentdan tashqarida (har render qayta yaralmasin — Misol 1).
- Memoizatsiyani o'lchovga asoslab (profiler keyin optimallashtir — premature emas — 2.13).
useMemo/useCallbackreferential equality uchun (memo'li bola, effekt deps — asosiy sabab — 2.9).React.memo+useMemo+useCallbackbirga (biri yolg'iz ko'pincha foydasiz — 2.12).exhaustive-deps'ga rioya (memo deps to'liq — 11.5: 2.6).- Arzon hisobni memoizatsiya qilma (
a + b, konstanta, oddiy funksiya — 2.13). - Memoizatsiyaga mantiqiy tayanma (faqat tezlik; kod usiz ham ishlasin — 2.8).
- React Compiler'ni ko'rib chiq (yangi loyiha — qo'lda memoizatsiyani kamaytiradi — 2.14).
9. Amaliy loyiha: "Byudjet Boshqaruvchi (Budget Tracker)"
Murakkab state (useReducer) va o'lchovli optimizatsiya (useMemo/useCallback) ni birga mustahkamlash.
Maqsad
Kirim/chiqimlarni boshqaradigan, statistika hisoblaydigan, filtrlaydigan byudjet ilovasi — barcha state mantig'i reducer'da, qimmat hisoblar memoizatsiyalangan.
Talablar (requirements)
- useReducer: tranzaksiyalar (kirim/chiqim) —
add/remove/edit/clearaction'lari (Misol 2). - Action payload: har action kerakli ma'lumotni payload bilan uzatsin 2.4-bob.
- Murakkab state: tranzaksiyalar + filtr + saralash bitta reducer'da yoki mantiqan ajratilgan 2.6-bob.
- useMemo statistika: umumiy balans, jami kirim, jami chiqim — memoizatsiyalangan (Misol 5).
- useMemo filtr: kategoriya/sana bo'yicha filtrlangan ro'yxat (Misol 7).
- useCallback: memoizatsiyalangan tranzaksiya satriga barqaror handler (Misol 8, 13).
- React.memo: tranzaksiya satri komponenti memoizatsiyalansin (faqat o'zgargani render — 2.12).
- localStorage: lazy init bilan saqlanganni yukla (Misol 4); o'zgarganda saqla (
useEffect— 11.5). - O'lchash: Profiler bilan tekshir — memoizatsiya haqiqatan render kamaytirdimi (2.13, Misol 14).
- Oqlanganlik: har
useMemo/useCallbackni nega qo'yganingni izohla (oddiy joyda ishlatma — 2.13).
Maslahatlar (hint)
- Reducer'ni komponentdan tashqarida, sof va immutable yoz (Misol 1, 2.3).
- Avval memoizatsiyasiz yoz, keyin Profiler bilan o'lcha — qayerda haqiqatan kerakligini ko'r 2.13-bob.
React.memo'li satr +useCallbackhandler birga ishlatilganda memo haqiqatan foyda beradi 2.12-bob.- Statistika va filtrlangan ro'yxat —
useMemo(qimmat, tez-tez render'da). Oddiytotalbo'lsa — ehtiyot bo'l (arzon). - Stale closure'dan saqlan: updater funksiya (
prev =>— 11.4: 2.6).
"Tayyor" mezonlari (acceptance criteria)
- Barcha state o'zgarishi reducer orqali (dispatch — tarqoq setX yo'q).
- Reducer sof va immutable (mutatsiya yo'q).
- Statistika
useMemobilan (qayta hisob faqat kerakli deps'da). - Filtr/saralash memoizatsiyalangan.
- Tranzaksiya satri
React.memo+ barqaroruseCallbackhandler. - Filter o'zgarganda faqat kerakli satrlar render bo'ladi (Profiler tasdiqlaydi).
- localStorage lazy init + saqlash ishlaydi.
- Har memoizatsiya oqlangan (oddiy joyda ortiqcha memo yo'q).
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda hooklar bilimini yakunladik:
useReducer(murakkab state — 2.2); reducer (sof,(state, action) => newState— 2.3); dispatch/action (type/payload — 2.4); anatomiya va lazy init 2.5-bob;useStatebilan solishtirish 2.6-bob.- Memoization (keshlash g'oyasi — 2.7);
useMemo(qimmat hisob — 2.8); referential equality (havola barqarorligi — 2.9);useCallback(funksiya keshlash — 2.10); ikkisining farqi 2.11-bob. React.memobilan bog'lanish (uchlik birga — 2.12); qachon optimallashtirMaslik (o'lcha, premature emas — 2.13); React Compiler (avto-memoizatsiya — 2.14).
Endi siz murakkab state mantig'ini tartibli boshqarish (useReducer) va keraksiz hisob/render'larni o'lchovga asoslanib to'xtatishni (useMemo/useCallback/React.memo) bilasiz. Eng muhimi — balansni tushunasiz: optimizatsiya — dalilga asoslangan, "har ehtimolga qarshi" emas.
Keyingi bob — 11.7-bob: Custom hooks (o'z hooklaringni yozish). Endi o'rgangan barcha hooklarni (useState, useEffect, useReducer, useMemo...) birlashtirib, o'z hookingizni yozasiz. Custom hook — bu mantiqni qayta ishlatishning React usuli: useFetch, useLocalStorage, useDebounce, useToggle kabi — bir marta yozilib, butun ilovada (va loyihalarda) qayta ishlatiladigan, sinaladigan mantiq bo'laklari. Bu — toza, modulli React kodning eng kuchli vositasi.
Foydalanilgan rasmiy/ishonchli manbalar
- React rasmiy hujjati — "Extracting State Logic into a Reducer", "Scaling Up with Reducer and Context" bo'limlari va
useReducerAPI ma'lumotnomasi - React rasmiy hujjati —
useMemovauseCallbackAPI ma'lumotnomasi; "Skipping expensive recalculations", "Memoizing a function" va hisobni keshlash bo'yicha qo'llanmalar - React rasmiy hujjati —
memo(React.memo) API ma'lumotnomasi; "Keeping Components Pure" (sof komponentlar); "React Compiler" bo'yicha rasmiy qo'llanma va o'rnatish yo'riqnomasi - React rasmiy hujjati — "Rules of Hooks" va
eslint-plugin-react-hooks(exhaustive-depsqoidasi) hujjati - MDN Web Docs —
Array.prototype.reduce, tenglik va taqqoslash (===— havola bo'yicha tenglik) - Kent C. Dodds — "When to useMemo and useCallback" (memoizatsiya narxi va oqlanishi bo'yicha amaliy tahlil)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!