WisarWisar
Dasturlash kitobi/11-QISM — React37 daqiqa

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 — useReduceruseStatening 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/useCallback esa — 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) useState yetmaydi; useReducer tartib beradi.
  • PerformanceuseMemo/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'prikuseReducer — Redux 12.2-bobning kichik modeli; uni tushunsangiz, Redux oson.

2. Nazariya — chuqur tushuntirish

2.1. Nega bu uch hook — re-render va keshlash

text
  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) uchun

Nega 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?) — useReducer barcha 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) — useMemo qimmat hisob natijasini keshlaydi, useCallback funksiya havolasini barqaror ushlaydi. Asosiy farq: useReducertartib uchun (state mantig'ini tashkil qilish); useMemo/useCallbacktezlik uchun (keraksiz hisob va render'larni to'xtatish). Endi har birini chuqur ko'ramiz.

2.2. useReducer nima va nega (useState chegarasi)

text
  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)

useReduceruseStatening kuchliroq muqobili, murakkab state mantig'i uchun. useState qachon 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 (tarqoq setXlar — chalkash). useReducer g'oyasi — state o'zgarishini markazlashtirish: barcha o'zgarish mantig'i bitta funksiyada (reducer) yashaydi; komponent faqat "nima sodir bo'ldi" (action) ni dispatch bilan 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: useReducerReduxning 12.2-bob komponent ichidagi kichik modeli (bir xil (state, action) => newState g'oyasi). useReducerni tushunsangiz, Redux sizga allaqachon tanish bo'ladi.

2.3. Reducer funksiya — pure, (state, action) => newState

text
  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 funksiyauseReducerning yuragi: eski state va action olib, yangi state qaytaradigan sof funksiya(state, action) => newState. Odatda ichida switch (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), va default holatda 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 (ular dispatchdan oldin yoki useEffectda). "Reducer" nomi Array.reducedan keladi 2.7-bob: u ham (akkumulyator, element) => yangiAkkumulyator shaklida 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

text
  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)

dispatch va actionuseReducerning ikkinchi qismi. dispatch — reducer'ga **"nima bo'ldi"**ni jo'natuvchi funksiya (useReducer qaytaradi). Action — sodir bo'lgan hodisani tasvirlovchi obyekt: type (majburiy — qanday o'zgarish, string — "increment", "add_todo") va ixtiyoriy payload (o'zgarish uchun kerakli ma'lumot — yangi element, id, filtr qiymati). Komponent shunchaki dispatch({ 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: type aniq 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

text
  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)

useReducer anatomiyasi — ikki argument oladi: reducer funksiya 2.3-bob va boshlang'ich state; va massiv qaytaradi: [state, dispatch] (joriy state va action jo'natuvchi). Tuzilishi useStatega 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'ni init(initialArg) funksiyasi bilan hisoblaydi (faqat birinchi render'da — qimmat boshlang'ich hisob uchun, masalan localStoragedan 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 faqat useReducer(reducer, initialState) chaqirasiz va dispatch bilan action jo'natasiz. Bu — toza, qayta ishlatiladigan struktura.

2.6. useState vs useReducer — qachon qaysi

text
  ┌──────────────────────────┬─────────────────┬─────────────────────┐
  │                          │ 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)

useState vs useReducer — 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 state useState; 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 doim useStatedan boshla (sodda), va faqat murakkablik o'sganda useReducerga ko'ch (oldindan, "ehtimol kerak bo'lar" deb optimallashtirma — 2.13). Ko'pincha useReducerga o'tish belgisi — bir nechta setX doim birga chaqirilayotgani yoki state mantig'i komponentni "to'ldirib" yuborganidir.

2.7. Memoization nima — keshlash g'oyasi

text
  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). useMemo buni hal qiladi: hisob natijasini keshlaydi va faqat dependency o'zgarganda qayta hisoblaydi (useMemo(() => qimmatHisob(items), [items])items o'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

text
  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 — items o'zgarmasa, qaytadan hisoblanmaydi. Qachon useMemo kerak: (1) haqiqatan qimmat hisob (katta massiv filter/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) useMemokafolat 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) komponent useMemosiz ham bir xil ishlashi kerak — useMemo faqat tezlikni o'zgartiradi, natijani emas. Agar useMemoni olib tashlaganda kod buzilsa — demak uni noto'g'ri ishlatilgan.

2.9. Referential equality — obyekt/massiv havolasini barqaror ushlash

text
  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 tayanadi

Referential 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 uni props sifatida bolaga uzatsangiz, bola har doim "yangi prop" ko'radi (memoizatsiyalangan bola ham keraksiz re-render bo'ladi — 2.12), yoki useEffect deps'iga qo'ysangiz cheksiz effekt (11.5: 2.9). YechimuseMemo (obyekt/massiv uchun) yoki useCallback (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

text
  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 uni React.memo'li bolaga uzatsangiz, bola keraksiz re-render bo'ladi — useCallback havolani barqaror ushlaydi (bola bir xil prop ko'radi re-render yo'q). Munosabati: useCallback(fn, deps) aynan useMemo(() => fn, deps)ga teng — useCallback funksiyaning o'zini keshlaydi, useMemo esa funksiya natijasini. Qachon useCallback kerak: (1) funksiyani React.memo'li bolaga prop sifatida uzatganda 2.12-bob; (2) funksiya useEffect/useMemo deps'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'lmagan onClick) useCallbackga o'rash foydasiz — u faqat kodni murakkablashtiradi 2.13-bob. useCallback faqat referential barqarorlik haqiqatan kerak bo'lganda mantiqli.

2.11. useMemo vs useCallback — farq va o'xshashlik

text
  ┌──────────────┬────────────────────────────┬──────────────────────────┐
  │              │ 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

useMemo vs useCallback — bir xil g'oyaning (memoizatsiya) ikki ko'rinishi, faqat nima keshlanishi bilan farq qiladi. useMemoqiymatni (hisob natijasini) keshlaydi: useMemo(() => hisob(a, b), [a, b]) hisob natijasini qaytaradi. useCallbackfunksiyani (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 uchun useMemo, funksiya havolasini barqaror ushlash uchun useCallback. 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)

text
  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.memo props'ni === bilan solishtiradi 2.9-bob — agar obyekt yoki funksiya prop uzatsangiz, u har render'da yangi havola oladi, shuning uchun memo "props o'zgardi" deb o'ylaydi va baribir render qiladi (memo foydasiz bo'lib qoladi). Yechim: obyekt prop'larni useMemo bilan, funksiya prop'larni useCallback bilan barqaror ushlash — shundagina React.memo haqiqatan ishlaydi. Demak React.memo + useMemo + useCallback uchalasi 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)

text
  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); useEffect deps 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)

text
  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 kerak

React 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 avtomatik useMemolangan 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

text
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)

jsx
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)

jsx
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)

jsx
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)

jsx
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)

jsx
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)

jsx
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 ishlatilish

Misol 7 — useMemo: filtrlangan ro'yxat (oqlangan holat — 2.8)

jsx
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)

jsx
// 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)

jsx
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)

jsx
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)

jsx
// 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)

jsx
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) — birga

Misol 13 — React.memo + useMemo + useCallback uchligi (2.12)

jsx
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)

jsx
// 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

text
 reducer ichida fetch/Math.random/state mutatsiya (sof emas — 2.3)
 reducer sof: faqat (state, action) => yangi state (immutable)

2) useState vs useReducer

text
 5+ bog'liq useState, tarqoq setX'lar (chalkash)
 murakkab bog'liq state  useReducer (markazlashgan — 2.6)

3) useMemo — referential equality

text
 const opt={...}; <Memo opt={opt}/>  (har render yangi havola  memo foydasiz — 2.9)
 const opt=useMemo(()=>({...}),[deps])  (barqaror havola)

4) useCallback + memo

text
 React.memo'li bolaga oddiy funksiya (har render yangi  memo ishlamaydi — 2.12)
 useCallback bilan barqaror funksiya (memo haqiqatan ishlaydi)

5) Ortiqcha memoizatsiya

text
 useMemo(() => a+b, [a,b])  (arzon hisob — ortiqcha — 2.13)
 const sum = a + b  (oddiy; memoizatsiya faqat qimmat/referential uchun)

6) Memoizatsiyaga mantiqiy tayanish

text
 useMemo natijasiga to'g'rilik uchun tayanish (React keshni tashlashi mumkin — 2.8)
 useMemo faqat TEZLIK; kod usiz ham bir xil ishlasin

6. 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: useReduceruseStatening murakkab muqobili; immutability bir xil 2.3-bob.
  • Hooks 11.5-bob: useMemo/useCallback object-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 (murakkablashsa useReducerga 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/useCallback referential equality uchun (memo'li bola, effekt deps — asosiy sabab — 2.9).
  • React.memo + useMemo + useCallback birga (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)

  1. useReducer: tranzaksiyalar (kirim/chiqim) — add/remove/edit/clear action'lari (Misol 2).
  2. Action payload: har action kerakli ma'lumotni payload bilan uzatsin 2.4-bob.
  3. Murakkab state: tranzaksiyalar + filtr + saralash bitta reducer'da yoki mantiqan ajratilgan 2.6-bob.
  4. useMemo statistika: umumiy balans, jami kirim, jami chiqim — memoizatsiyalangan (Misol 5).
  5. useMemo filtr: kategoriya/sana bo'yicha filtrlangan ro'yxat (Misol 7).
  6. useCallback: memoizatsiyalangan tranzaksiya satriga barqaror handler (Misol 8, 13).
  7. React.memo: tranzaksiya satri komponenti memoizatsiyalansin (faqat o'zgargani render — 2.12).
  8. localStorage: lazy init bilan saqlanganni yukla (Misol 4); o'zgarganda saqla (useEffect — 11.5).
  9. O'lchash: Profiler bilan tekshir — memoizatsiya haqiqatan render kamaytirdimi (2.13, Misol 14).
  10. 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 + useCallback handler birga ishlatilganda memo haqiqatan foyda beradi 2.12-bob.
  • Statistika va filtrlangan ro'yxat — useMemo (qimmat, tez-tez render'da). Oddiy total bo'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 useMemo bilan (qayta hisob faqat kerakli deps'da).
  • Filtr/saralash memoizatsiyalangan.
  • Tranzaksiya satri React.memo + barqaror useCallback handler.
  • 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; useState bilan 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.memo bilan 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 useReducer API ma'lumotnomasi
  • React rasmiy hujjati — useMemo va useCallback API 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-deps qoidasi) 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!
11.6-bob: useMemo, useCallback, useReducer — Wisar