WisarWisar
Dasturlash kitobi/11-QISM — React45 daqiqa

11.5-bob: Hooks — useState, useEffect, useContext, useRef

11-QISM — Frontend: React · 5-mavzu


1. Kirish va motivatsiya

11.4-bobda useState bilan birinchi hook'ni ishlatdik va ilovamizga "xotira" berdik. Lekin useState — bu butun bir oilaning faqat bitta a'zosi. Hooklar — bu React'ning eng katta inqilobi (2018-yil, 16.8 versiya): ular funksiya komponentlarni o'zgartirib, ularga shu paytgacha faqat class komponentlarda mavjud bo'lgan barcha imkoniyatlarni (state, hayot sikli, kontekst) berdi — va buni ancha sodda, qayta ishlatiladigan tarzda qildi. Bugun hech kim yangi React kodini class bilan yozmaydi; butun zamonaviy React — funksiya + hooklar ustiga qurilgan.

Bu bobda biz to'rtta eng muhim hookni chuqur o'rganamiz. useState (xotira — 11.4'da o'rgandik, qisqa takror) — komponent state'i. useEffect — komponentni tashqi dunyo bilan bog'lash (API chaqiruvi, taymer, obuna, DOM bilan ishlash) — bu eng kuchli, lekin eng ko'p noto'g'ri ishlatiladigan hook. useContext — ma'lumotni props drillingsiz (har qatlamdan qo'lda uzatmasdan) butun daraxt bo'ylab ulashish (mavzu, til, autentifikatsiya). useRef — DOM elementiga to'g'ridan kirish va re-render'siz qiymat saqlash. Va eng muhimi — barcha hooklar bo'ysunadigan ikkita qoida: Rules of Hooks — ularni nega shunday yozish kerakligini chuqur tushunamiz (bu yodlash emas, React'ning ichki mexanizmidan kelib chiqadigan zaruriyat).

Bu bob: hook nima va nega (class'dan hooklarga o'tish tarixi), Rules of Hooks (nega funksiya tepasida, nega shart/tsikl ichida emas — React hooklarni chaqiruv tartibi bilan kuzatishi), useEffect (side effect nima, dependency array, cleanup, "sinxronlash" mental modeli, eng keng tuzoqlar — missing deps, infinite loop, stale closure), qachon useEffect KERAK EMAS (react.dev'ning muhim ogohlantirishi — derived state, event handlerda effect ishlatmaslik), useContext (props drilling Provider/Consumer), useRef (DOM kirish va render'siz mutable qiymat). Bundan tashqari, amaliyotda hal qiluvchi — stale closure, "You Might Not Need an Effect", useRef vs useState farqi — ham qamraladi.

O'xshatish: Hooklar — komponentning organlari va sezgi a'zolari. useStatexotira (komponent nimani esda saqlaydi). useEffect — komponentning tashqi dunyo bilan aloqasi: ko'zlari (serverdan ma'lumot oladi), quloqlari (hodisalarni tinglaydi), qo'llari (taymer o'rnatadi, DOM'ga tegadi) — va eng muhimi, tartib-intizomi: ish tugagach orqasini yig'ishtiradi (cleanup — taymerni o'chiradi, obunani bekor qiladi). useContextumumiy radio to'lqini: butun ilova bir kanalga ulanib, markazdan kelgan ma'lumotni (mavzu, til) eshitadi — har biriga alohida sim tortish (props drilling) shart emas. useRef — komponentning cho'ntak daftarchasi: unga yozasiz, lekin yozganingiz hech kimga ko'rinmaydi va sizni "qayta tug'ilishga" (re-render) majburlamaydi — DOM elementiga ishora yoki esda tutiladigan, lekin ekranga chiqmaydigan qiymat uchun.

Nega muhim?

  • Real ilova nafasi — har React loyihada API chaqiruvi (useEffect), global ma'lumot (useContext), DOM kirish (useRef) bor.
  • Eng ko'p xato useEffectda — stale closure, infinite loop, missing deps — junior'ning eng katta tuzoqlari shu yerda.
  • "Effect kerak emas" bilimi — keraksiz effect — sekin va xato kod; buni bilmaslik — senior'dan junior'ni ajratadi.
  • Custom hooklar poydevori — 11.7'da o'z hooklaringizni yozasiz; avval bularni puxta bilish kerak.

2. Nazariya — chuqur tushuntirish

2.1. Hook nima va nega (class hooklar)

text
  HOOK — funksiya komponentga React imkoniyatlarini "ulaydigan" maxsus funksiya
         (nomi "use" bilan boshlanadi: useState, useEffect, useRef, useContext...)

  TARIX (nega hooklar paydo bo'ldi):
  ESKI (class komponent — murakkab):
  class Counter extends React.Component {
    constructor() { super(); this.state = { count: 0 }; }
    componentDidMount() { /* mount */ }
    componentDidUpdate() { /* update */ }
    componentWillUnmount() { /* cleanup */ }
    render() { return <button onClick={() => this.setState(...)}>...</button>; }
  }
  MUAMMOLAR: this chalkash, mantiq 3 metodga bo'linib ketadi, qayta ishlatish qiyin (HOC do'zaxi)

  YANGI (funksiya + hook — sodda):
  function Counter() {
    const [count, setCount] = useState(0);
    useEffect(() => { /* mount + update + cleanup — BIR joyda */ });
    return <button onClick={() => setCount(count + 1)}>{count}</button>;
  }

   Hooklar (2018, React 16.8): this yo'q, mantiq birga, qayta ishlatish oson (custom hook — 11.7)

Hook — funksiya komponentga React imkoniyatlarini (state, hayot sikli, kontekst) "ulaydigan" maxsus funksiya; nomi har doim use bilan boshlanadi (useState, useEffect, useRef, useContext). Hooklar nega paydo bo'ldi: eski React'da state va hayot sikli faqat class komponentlarda mavjud edi (this.state, componentDidMount, componentWillUnmount), va bu uch muammoni keltirardi: (1) this chalkashligi (bog'lash, kontekst); (2) bog'liq mantiq uch xil metodga bo'linib ketardi (masalan obunani ochish componentDidMountda, yopish componentWillUnmountda — ajralgan); (3) mantiqni komponentlar orasida qayta ishlatish qiyin edi (HOC/render props "do'zaxi" — 11.13). Hooklar (2018, React 16.8) bularning hammasini hal qildi: this yo'q, bog'liq mantiq bir joyda (useEffect ichida ochish va cleanup birga), va mantiqni custom hook sifatida osongina qayta ishlatish 11.7-bob. Bugun zamonaviy React butunlay funksiya + hook ustiga quriladi; class komponentlar eski kodda qoladi, lekin yangi kod yozmaysiz.

2.2. Rules of Hooks — nega tepada, nega shartsiz (chuqur)

text
  IKKI QOIDA (qat'iy):
  1. Hooklarni faqat ENG YUQORIDA chaqir (shart, tsikl, ichki funksiya ICHIDA EMAS)
  2. Hooklarni faqat React funksiyalarida chaqir (komponent yoki custom hook — 11.7)

  NEGA? React hooklarni NOM bilan emas, CHAQIRUV TARTIBI bilan kuzatadi:
  function Form() {
    const [name, setName] = useState("");     // hook #1
    const [age, setAge] = useState(0);        // hook #2
    useEffect(() => {...});                   // hook #3
    // React ichida: [#1: name, #2: age, #3: effect] — TARTIB bo'yicha massiv
  }

   SHART ICHIDA — tartib BUZILADI:
  if (loggedIn) {
    const [name, setName] = useState("");     // ba'zan #1, ba'zan YO'Q!
  }                                            //  React tartibni yo'qotadi  state aralashadi

  ┌────────────────────────────────────────────────────────────┐
  │ Render 1 (loggedIn=true):  [#1 name, #2 age]                │
  │ Render 2 (loggedIn=false): [#1 age]  name o'tib ketdi!     │
  │  React #1 ni "name" deb bilardi, endi "age"  FALOKAT      │
  └────────────────────────────────────────────────────────────┘

   Hooklar HAR render'da BIR XIL TARTIB, BIR XIL SONDA chaqirilishi SHART
   ESLint plugin (eslint-plugin-react-hooks) buni avtomatik tekshiradi (15.3)

Rules of Hooks — ikkita qat'iy qoida: (1) hooklarni faqat komponentning eng yuqorisida chaqir — shart, tsikl, ichki funksiya ichida emas; (2) hooklarni faqat React funksiyalarida (komponent yoki custom hook) chaqir. Nega bu qoidalar? Chunki React hooklarni ularning nomi bilan emas, chaqiruv tartibi bilan kuzatadi: har render'da hooklar ketma-ket chaqiriladi va React ularni ichki massivda tartib raqami bo'yicha saqlaydi ([#1, #2, #3]). Agar hookni shart ichida qo'ysangiz, ba'zan u chaqiriladi, ba'zan yo'q — tartib siljiydi va React #1ni bir render'da "name", boshqasida "age" deb biladi state aralashadi, kutilmagan xatolar. Demak hooklar har render'da bir xil tartibda, bir xil sonda chaqirilishi shart. Shart kerak bo'lsa — uni hook ichida qo'yish kerak (useEffect(() => { if (x) {...} })), hookni shart ichida emas. Bu qoidani eslint-plugin-react-hooks avtomatik tekshiradi (har React loyihada yoqilgan bo'lsin — 15.3) — u xatolarni yozish paytining o'zida tutadi.

2.3. useState — ko'p state va boshqaruv (qisqa takror)

text
  KOMPONENTDA ISTAGANCHA state bo'lishi mumkin (har biri mustaqil):
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [loading, setLoading] = useState(false);

  ALOHIDA state vs BITTA obyekt state — qaysi biri?
   Alohida (oddiy, mustaqil maydonlar):      const [a]=.. const [b]=..
   Obyekt (birga o'zgaradigan, forma):       const [form, setForm] = useState({a, b})
   ikkalasi to'g'ri; bog'liqligi va soni bo'yicha tanlanadi (juda ko'p bo'lsa — useReducer 11.6)

   Bir-biriga bog'liq state'larni alohida tutsang — sinxronlash muammosi (useReducer afzal)
   Mustaqil, oddiy state'lar — alohida toza (form butun bo'lsa — obyekt)

useState — ko'p state — komponentda istalgancha state bo'lishi mumkin, har biri mustaqil (name, email, loading). Savol: alohida state'lar (const [a], const [b]) yoki bitta obyekt state (useState({a, b}))? Ikkalasi ham to'g'ri, tanlov bog'liqlikga qarab: mustaqil, oddiy maydonlar — alohida (toza, har biri o'zicha); birga o'zgaradigan, mantiqan bog'liq maydonlar (forma) — bitta obyekt (11.4: 2.8). Agar state'lar bir-biriga kuchli bog'liq bo'lsa va birga yangilansa, ularni alohida tutish sinxronlash muammosini keltirishi mumkin — bunda useReducer 11.6-bob afzal (bir nechta bog'liq state'ni bitta mantiqda boshqaradi). Hozircha qoida: oddiy mustaqil qiymat — useState; murakkab bog'liq mantiq — useReducer (11.6'da o'rganamiz). Bu bobda asosiy e'tibor — useEffect, useContext, useRef.

2.3a. useState — lazy init va funksional update (chuqur)

text
  LAZY INIT (dangasa boshlang'ich qiymat) — boshlang'ich qiymat QIMMAT bo'lganda:
   const [state, set] = useState(qimmatHisob());     // qimmatHisob() HAR render'da chaqiriladi!
   const [state, set] = useState(() => qimmatHisob()); // funksiya — FAQAT birinchi render'da

   useState argumenti FUNKSIYA bo'lsa, React uni faqat mount'da bir marta chaqiradi
    (masalan localStorage'dan o'qish, katta massiv qurish — har render'da takrorlanmasin)

  FUNKSIONAL UPDATE (updater funksiya) — yangi qiymat ESKISIGA bog'liq bo'lganda:
   setCount(count + 1); setCount(count + 1);   // ikkalasi ham BIR xil snapshot count'dan  +1
   setCount(c => c + 1); setCount(c => c + 1); // React navbatga qo'yadi  +2 (11.4: 2.6)

  ┌────────────────────────────────────────────────────────────────┐
  │ set(yangiQiymat)   — to'g'ridan qiymat (eskiga bog'liq emas)     │
  │ set(esk => yangi)  — updater; esk = navbatdagi eng yangi qiymat  │
  └────────────────────────────────────────────────────────────────┘

   Lazy init: argument funksiya (chaqiruv EMAS) — useState(fn), useState(fn()) EMAS
   Updater: asinxron/taymer/ketma-ket setX'da stale closure'dan himoya (2.9)

useState — lazy init va funksional update — ikki muhim nozik nuqta. (1) Lazy init: useStatega berilgan boshlang'ich qiymat har render'da qayta hisoblanadi (garchi React faqat birinchisini ishlatsa ham) — agar u qimmat bo'lsa (masalan localStorage'dan o'qish, katta massiv qurish), o'rniga funksiya bering: useState(() => qimmatHisob()). React funksiya-argumentni faqat mount'da bir marta chaqiradi, keyingi render'larda tegmaydi. Diqqat: useState(fn) (funksiyaning o'zi) — useState(fn()) (uni chaqirib qiymatini berish) emas. (2) Funksional update (updater): agar yangi qiymat eskisiga bog'liq bo'lsa, setCount(count + 1) o'rniga setCount(c => c + 1) yozing. Sababi — count render snapshot'idan olinadi (11.4: 2.3), shuning uchun bir handlerda setCount(count + 1) ni ikki marta chaqirsangiz ikkalasi ham bir xil eski count'ni ko'radi (+1 bo'lib qoladi); updater esa navbatdagi eng yangi qiymatni oladi (+2). Updater — asinxron kod, taymer, ketma-ket yangilashda stale closure'dan asosiy himoya (2.9, Misol 8).

2.4. Side effect nima — pure render vs effect

text
  PURE RENDER (komponent funksiyasi — toza bo'lishi kerak — 11.2):
   faqat props/state'dan JSX HISOBLAYDI, boshqa hech narsa qilmaydi
   hech qanday "nojo'ya ish" yo'q (server chaqiruvi, DOM o'zgartirish, taymer)

  SIDE EFFECT (nojo'ya ta'sir) — render'dan TASHQARIDAGI dunyoga ta'sir:
  - serverdan ma'lumot olish (fetch — 12.4)
  - taymer/interval o'rnatish (setInterval)
  - hodisaga obuna (addEventListener, WebSocket — 5.13)
  - DOM'ni qo'lda o'zgartirish (document.title, focus)
  - localStorage'ga yozish

   Effect'ni render PAYTIDA bajarma (komponent nopok bo'ladi, ikki marta ishlaydi — 11.2: 2.11)
   Effect'ni useEffect ICHIDA bajar  React uni RENDER'dan KEYIN (commit'dan so'ng) ishga tushiradi

  ┌──────────────────────────────────────────────────────────┐
  │ Render (toza hisob)    Ekran (commit)    useEffect ishlaydi│
  └──────────────────────────────────────────────────────────┘

Side effect (nojo'ya ta'sir)useEffectni tushunish uchun avval shuni bilish kerak. Komponent funksiyasi toza (pure) bo'lishi kerak (11.2: 2.2): u faqat props/state'dan JSX hisoblaydi, boshqa hech narsa qilmaydi. Side effect — bu render'dan tashqaridagi dunyoga ta'sir qiladigan har qanday ish: serverdan ma'lumot olish (fetch — 12.4), taymer o'rnatish (setInterval), hodisaga obuna (addEventListener, WebSocket — 5.13), DOM'ni qo'lda o'zgartirish (document.title, focus), localStorage'ga yozish. Bu ishlarni render paytida bajarib bo'lmaydi (komponent nopok bo'ladi, StrictMode'da ikki marta ishlaydi, kutilmagan xatolar — 11.2: 2.11). O'rniga ularni useEffect ichida bajarasiz — React useEffectni render va ekranga chizishdan (commit) keyin ishga tushiradi. Demak tartib: render (toza hisob) ekran yangilanadi useEffect ishlaydi. Bu — toza render va nojo'ya ta'sirni ajratishning React usuli.

2.5. useEffect anatomiyasi — sintaksis va qachon ishlaydi

text
  useEffect(setup, dependencies):

  useEffect(() => {
    // SETUP — effekt mantiqi (render'dan KEYIN ishlaydi)
    console.log("Effekt ishladi");

    return () => {
      // CLEANUP — tozalash (ixtiyoriy — keyingi effekt/unmount'dan OLDIN — 2.7)
      console.log("Tozalandi");
    };
  }, [dependencies]);   // BOG'LIQLIKLAR massivi (qachon qayta ishlashni belgilaydi — 2.6)

  3 QISM:
  1. setup funksiya     — nima qilish (effekt)
  2. cleanup (return)   — orqani yig'ishtirish (ixtiyoriy)
  3. dependency array   — qachon ishlash (yo'q / [] / [a, b])

  QACHON ISHLAYDI:
  - Komponent ekranga chizilgach (mount'dan keyin)
  - dependency o'zgargach (qayta render + dep boshqacha)
  - Komponent yo'qolishdan oldin cleanup (unmount)

   Render PAYTIDA emas, render'dan KEYIN (ekran allaqachon yangilangan)

useEffect anatomiyasi — ikki argument oladi: setup funksiya (effekt mantiqi) va dependency array (bog'liqliklar). Setup funksiya ixtiyoriy ravishda cleanup funksiya (return () => {...}) qaytarishi mumkin 2.7-bob. Demak uch qism: (1) setup — nima qilish (fetch, taymer); (2) cleanup — orqani yig'ishtirish (taymerni o'chirish, obunani bekor qilish); (3) dependency array — qachon qayta ishlash. Qachon ishlaydi: komponent ekranga chizilgach (mount'dan keyin — render paytida emas, keyin), dependency o'zgarganda (qayta render + bog'liqlik boshqacha bo'lsa), va komponent yo'qolishdan oldin cleanup ishlaydi (unmount). Eng muhim: useEffect har doim render va ekpanga chizishdan keyin ishlaydi (foydalanuvchi avval yangi UI'ni ko'radi, keyin effekt ishga tushadi) — shuning uchun effekt ichida DOM allaqachon mavjud, va effekt foydalanuvchini "bloklamaydi". Dependency array — useEffectni to'g'ri ishlatishning kaliti 2.6-bob.

2.6. Dependency array — yo'q / [] / [deps]

text
  DEPENDENCY ARRAY uch holat — effekt QACHON qayta ishlashni belgilaydi:

  1. ARRAY YO'Q — HAR render'dan keyin ishlaydi (kamdan-kam kerak, ehtiyotkorlik):
  useEffect(() => { console.log("har render") });

  2. BO'SH ARRAY [] — FAQAT BIR MARTA (mount'da — komponent paydo bo'lganda):
  useEffect(() => { fetchData(); }, []);   // boshlang'ich yuklash uchun ideal

  3. [a, b] — a yoki b O'ZGARganda ishlaydi (kuzatish):
  useEffect(() => { fetchUser(userId); }, [userId]);  // userId o'zgarsa qayta yukla

  ┌──────────────┬─────────────────────────────────────────────┐
  │ deps         │ Effekt qachon ishlaydi                        │
  ├──────────────┼─────────────────────────────────────────────┤
  │ (yo'q)       │ HAR render'dan keyin                          │
  │ []           │ faqat 1 marta (mount)                         │
  │ [a, b]       │ mount + a yoki b o'zgarganda                  │
  └──────────────┴─────────────────────────────────────────────┘

   QOIDA: effekt ICHIDA ishlatilgan har bir o'zgaruvchi (props/state) deps'da BO'LISHI shart
   ESLint (exhaustive-deps) yetishmagan bog'liqlikni ogohlantiradi — quloq sol! (2.9)

Dependency arrayuseEffectni qachon qayta ishlashni belgilaydi, uch holat: (1) array yo'q — har render'dan keyin ishlaydi (kamdan-kam to'g'ri, ehtiyotkorlik talab qiladi); (2) bo'sh [] — faqat bir marta, mount'da (komponent birinchi paydo bo'lganda) — boshlang'ich ma'lumot yuklash, bir martalik obuna uchun ideal; (3) [a, b]a yoki b o'zgarganda ishlaydi (masalan [userId]userId o'zgarsa ma'lumotni qayta yuklash). Eng muhim qoida: effekt ichida ishlatilgan har bir reaktiv qiymat (props, state, ulardan hosil bo'lgan narsa) dependency array'da bo'lishi shart — aks holda effekt eski qiymatlarni "ko'radi" (stale closure — 2.9). eslint-plugin-react-hooksning exhaustive-deps qoidasi yetishmagan bog'liqlikni ogohlantiradi — bu ogohlantirishni e'tiborsiz qoldirmang (deps'ni qo'lda "aldamang"). Agar effekt juda tez-tez ishlasa, sababi odatda — object/function dependency 2.9-bob yoki effekt umuman kerak emas 2.10-bob.

2.6a. Effekt ichida async — nega setup async bo'lolmaydi

text
   setup funksiyaning O'ZINI async qilib bo'lmaydi:
  useEffect(async () => {              // async funksiya Promise qaytaradi
    const data = await fetch(...);     // React esa cleanup FUNKSIYA kutadi (Promise emas)
  }, []);                               //  cleanup ishlamaydi, ogohlantirish

   async ishni ICHKI funksiyada bajar (setup'ning o'zi sinxron qoladi):
  useEffect(() => {
    let ignore = false;                          // race himoyasi (Misol 3)
    async function load() {
      const data = await fetchUser(userId);
      if (!ignore) setUser(data);                // faqat hali aktual bo'lsa
    }
    load();
    return () => { ignore = true; };             // cleanup — oddiy sinxron funksiya
  }, [userId]);

   setup HAR doim sinxron; async'ni ichki funksiyaga o'ra, keyin chaqir
   Cleanup funksiya HECH QACHON async bo'lmaydi (React uni darhol chaqiradi)

Effekt ichida async — keng tuzoq: useEffect(async () => {...}) deb yozib bo'lmaydi. Sababi — async funksiya doim Promise qaytaradi, React esa setup'dan cleanup funksiya (yoki undefined) kutadi — Promise'ni cleanup deb ishlata olmaydi, natijada cleanup ishlamaydi va konsol ogohlantiradi. To'g'ri naqsh: setup'ning o'zini sinxron qoldirib, async/await ishini ichki funksiyaga o'rab, uni darhol chaqirish (async function load() {...} load();), va returnda oddiy sinxron cleanup berish. Bu naqsh race condition himoyasi (ignore bayrog'i yoki AbortController — Misol 3, 14) bilan birga — real fetch effektining standarti. Cleanup funksiya ham hech qachon async bo'lmaydi — React uni sinxron, darhol chaqiradi.

2.7. Cleanup funksiya — qachon va nega

text
  CLEANUP (return () => {...}) — effekt "orqasini yig'ishtiradi" (resurs bo'shatadi)

  QACHON ishlaydi:
  - Keyingi effekt ishlashdan OLDIN (dependency o'zgarganda — eskini tozala, keyin yangisi)
  - Komponent yo'qolishdan oldin (unmount — butunlay tozala)

  NEGA KERAK — resurs sizib ketmasligi (memory leak) uchun:
  useEffect(() => {
    const id = setInterval(() => tick(), 1000);   // taymer o'rnatildi
    return () => clearInterval(id);               //  komponent yo'qolsa — taymerni O'CHIR
  }, []);
  //  cleanup bo'lmasa: komponent yo'qolsa ham taymer ishlayveradi (leak + xato)

  TIPIK CLEANUP holatlari:
  - clearInterval / clearTimeout (taymer)
  - removeEventListener (hodisa)
  - socket.disconnect() / unsubscribe() (obuna — 5.13)
  - AbortController.abort() (fetchni bekor qilish — 12.4)

   StrictMode (dev) effektni IKKI marta ishga tushiradi (setupcleanupsetup)
      cleanup TO'G'RI yozilgan bo'lsa, muammo yo'q (bu ataylab — leak'ni fosh qiladi — 11.2: 2.11)

Cleanup funksiyauseEffect setup'i qaytaradigan funksiya (return () => {...}); u effekt "orqasini yig'ishtiradi" (resurslarni bo'shatadi). Qachon ishlaydi: (1) keyingi effekt ishlashdan oldin (dependency o'zgarganda — avval eskini tozala, keyin yangisini o'rnatadi); (2) komponent yo'qolishdan oldin (unmount — butunlay tozala). Nega kerak: resurs sizib ketmasligi (memory leak) uchun — masalan setInterval o'rnatib, cleanup yozmasangiz, komponent yo'qolsa ham taymer ishlayveradi (xotira oqib ketadi, yo'q komponentning state'ini yangilamoqchi bo'lib xato beradi). Tipik cleanup holatlari: clearInterval/clearTimeout (taymer), removeEventListener (hodisa), unsubscribe()/socket.disconnect() (obuna — 5.13), AbortController.abort() (fetchni bekor qilish — 12.4). StrictMode (development) effektni ataylab ikki marta ishga tushiradi (setup cleanup setup) — agar cleanup to'g'ri yozilgan bo'lsa muammo bo'lmaydi; bu mexanizm cleanup'ni unutgan joylaringni fosh qiladi (production'da bir marta — 11.2: 2.11). Demak cleanup — ixtiyoriy emas, resurs band qiluvchi har effekt uchun majburiy.

2.8. useEffect — "sinxronlash" modeli (lifecycle emas)

text
  ESKI (NOTO'G'RI) MENTAL MODEL — "hayot sikli" (lifecycle):
  "useEffect(() => {}, []) — bu componentDidMount"  CHALKASH va xato keltiradi

  YANGI (TO'G'RI) MENTAL MODEL — "SINXRONLASH" (synchronization):
  "useEffect — komponentni TASHQI tizim bilan SINXRON ushlab turish"

  Misol: chat xonasiga ulanish (roomId state'ga qarab):
  useEffect(() => {
    const conn = connectToRoom(roomId);   // SINXRON: roomId qanday bo'lsa, shu xonaga ulan
    return () => conn.disconnect();        // roomId o'zgarsa: eskidan uzil, yangiga ulan
  }, [roomId]);

   roomId="A": ulanish A. roomId="B" bo'ldi: A'dan uzil (cleanup)  B'ga ulan (setup)
   React effektni UI'ni state bilan sinxron ushlagandek, tashqi tizimni ham sinxron ushlaydi

   "Effekt qachon ishlaydi?" emas, "effekt NIMANI sinxron ushlaydi?" deb o'yla
   deps — "qaysi qiymat o'zgarsa qayta sinxronlash kerak" (lifecycle vaqti emas)

useEffect — sinxronlash modeli — bu hookni to'g'ri tushunishning kaliti. Ko'p dasturchi useEffectni eski class hayot sikli (lifecycle — componentDidMount/Update/Unmount) deb o'ylaydi — bu chalkash va xatoga olib keladi. To'g'ri model: useEffect — komponentni tashqi tizim bilan sinxron ushlab turadi. Masalan, chat xonasiga ulanish: roomId state'i "A" bo'lsa, A xonasiga ulanasiz; roomId "B" bo'ldi — React avtomatik A'dan uziladi (cleanup) va B'ga ulanadi (setup). Siz "qachon ulanish/uzilish"ni emas, "qaysi xonaga ulangan bo'lishim kerak" ni tasvirlaysiz — React qolganini qiladi (xuddi UI = f(state) — tashqi tizim ham state bilan sinxron). Demak "effekt qachon ishlaydi?" deb emas, "effekt nimani tashqi dunyo bilan sinxron ushlaydi?" deb o'ylash kerak; dependency array — "qaysi qiymat o'zgarsa qayta sinxronlash kerak" (lifecycle vaqti emas). Bu mental model effektlarni to'g'ri yozish va tuzoqlardan 2.9-bob qochishning asosi.

2.9. useEffect tuzoqlari — infinite loop va stale closure

text
  TUZOQ 1 — INFINITE LOOP (cheksiz tsikl):
   useEffect(() => { setCount(count + 1); });   // deps yo'q  har render setX  render  ...
   useEffect(() => { setData(fetch()); }, [data]); // data o'zgaradi  effekt  data  ...
   to'g'ri deps: [] (bir marta) yoki kerakli bog'liqlik (object dep'dan ehtiyot bo'l)

  TUZOQ 2 — OBJECT/FUNCTION DEPENDENCY (har render'da yangi havola):
   const options = { id: 5 };                  // har render'da YANGI obyekt (yangi havola)
     useEffect(() => {...}, [options]);          //  har render'da "o'zgargan" deb ko'rinadi  tsikl
   primitiv dep: }, [options.id])  yoki  obyektni effekt ichida yarat / useMemo 11.6-bob

  TUZOQ 3 — STALE CLOSURE (eskirgan qiymat — eng nozik):
   useEffect(() => {
       const id = setInterval(() => setCount(count + 1), 1000); // count MOUNT'dagi qiymatda QOTGAN
       return () => clearInterval(id);
     }, []);   // count har doim 0 (effekt 1 marta yaratilgan, count o'sha render'dan — 11.4: 2.3)
   updater funksiya: setInterval(() => setCount(c => c + 1), 1000)  // c — har doim yangi (11.4: 2.6)

   Ko'p tuzoq deps'ni "aldash"dan keladi  ESLint exhaustive-deps'ga quloq sol (2.6)

useEffect tuzoqlari — junior'ning eng katta xatolari shu yerda. Tuzoq 1 — infinite loop: effekt ichida state'ni yangilab, o'sha state'ni deps'ga qo'ysangiz (yoki deps yo'q bo'lsa) — render effekt setState render effekt... cheksiz tsikl; yechim — to'g'ri deps ([] yoki kerakli bog'liqlik). Tuzoq 2 — object/function dependency: komponent ichida yaratilgan obyekt/funksiya har render'da yangi havola oladi (11.4: 2.7), shuning uchun uni deps'ga qo'ysangiz React har doim "o'zgargan" deb ko'radi tsikl; yechim — primitiv dep ([options.id]), yoki obyektni effekt ichida yarat, yoki useMemo/useCallback 11.6-bob. Tuzoq 3 — stale closure (eng nozik): effekt [] deps bilan bir marta yaratiladi va ichidagi state qiymati o'sha render'dan qotib qoladi (11.4: 2.3 snapshot) — masalan setInterval ichidagi count har doim 0; yechim — updater funksiya (setCount(c => c + 1)c har doim eng yangi — 11.4: 2.6). Ko'p tuzoq deps'ni "aldash"dan (qo'lda noto'g'ri yozish) kelib chiqadi — exhaustive-deps ESLint qoidasiga quloq sol (u to'g'ri yo'lni ko'rsatadi).

2.10. Qachon useEffect KERAK EMAS (muhim!)

text
  KENG XATO: hamma narsaga useEffect ishlatish (react.dev maxsus ogohlantiradi)

   KERAK EMAS — HOSILANgan ma'lumot (state'dan hisoblanadi):
  const [first, setFirst] = useState(""); const [last, setLast] = useState("");
  const [full, setFull] = useState("");
  useEffect(() => { setFull(first + " " + last); }, [first, last]); //  ortiqcha render + effekt
   const full = first + " " + last;   // render PAYTIDA hisobla (state EMAS — 11.4: 2.14)

   KERAK EMAS — HODISAGA javob (event handler'da qil):
  useEffect(() => { if (submitted) sendData(); }, [submitted]); //  chalkash, ortiqcha state
   function handleSubmit() { sendData(); }   // to'g'ridan handler'da

  useEffect QACHON KERAK (haqiqiy side effect — tashqi tizim bilan sinxronlash):
   Serverdan ma'lumot olish (mount'da yoki id o'zgarganda — 12.4)
   Tashqi tizimga obuna (WebSocket, event listener, taymer)
   DOM bilan qo'lda ishlash (title, focus, o'lchov)

   "Bu effekt tashqi dunyo bilan sinxronlaydimi?" — YO'Q bo'lsa, effekt KERAK EMAS
   Derived state'ni render'da hisobla; hodisani handler'da qil (effekt emas)

Qachon useEffect KERAK EMAS — react.dev maxsus "You Might Not Need an Effect" sahifasi bilan ogohlantiradigan keng xato. Ikki asosiy noto'g'ri ishlatish: (1) hosilangan (derived) ma'lumotni effekt bilan hisoblash — masalan first + last'dan fullni effektda hisoblab, state'ga saqlash — bu ortiqcha (qo'shimcha render, sinxronlash muammosi); to'g'risi — render paytida hisoblash (const full = first + " " + last — state emas — 11.4: 2.14); (2) hodisaga javobni effekt bilan boshqarish — masalan submitted state'ni kuzatib effektda yuborish — chalkash; to'g'risi — to'g'ridan event handlerda qilish (handleSubmit). useEffect qachon haqiqatan kerak: faqat haqiqiy side effect — tashqi tizim bilan sinxronlash: serverdan ma'lumot 12.4-bob, tashqi obuna (WebSocket/taymer/listener), DOM bilan qo'lda ishlash (title/focus). Oltin test savoli: "bu effekt komponentni tashqi dunyo bilan sinxronlaydimi?" — javob "yo'q" bo'lsa (faqat ma'lumot o'zgartirish, hisoblash), effekt kerak emas. Bu bilim — keraksiz effektlardan (sekin, xato manbai) qutilishning va senior darajasida kod yozishning kaliti.

2.11. useContext — props drilling'siz ma'lumot ulashish

text
  MUAMMO — PROPS DRILLING (props'ni ko'p qatlam orqali "burg'ulab" o'tkazish):
  App (theme)  Page (theme)  Layout (theme)  Sidebar (theme)  Button (theme)
  // theme faqat Button'ga kerak, lekin HAR qatlamdan qo'lda uzatamiz (zerikarli, mo'rt)

  YECHIM — CONTEXT (markaziy "radio to'lqini" — istalgan chuqurlikdan o'qiladi):

  1. Context yarat (alohida faylda):
  const ThemeContext = createContext("light");   // default qiymat

  2. Provider bilan o'ra (ma'lumot manbai — yuqorida):
  <ThemeContext.Provider value={theme}>
    <App />                          {/* App va uning butun ostki daraxti theme'ni o'qiy oladi */}
  </ThemeContext.Provider>
  // React 19: to'g'ridan <ThemeContext value={theme}> (.Provider'siz)

  3. Istalgan bola o'qiydi (props drilling'siz):
  const theme = useContext(ThemeContext);   // to'g'ridan oladi (qatlamlar oraliq emas)

  QACHON Context: theme, til (i18n), autentifikatsiya (user), savat — GLOBAL/yarim-global ma'lumot
   Context — props drilling'ni yo'qotadi, LEKIN tez-tez o'zgaradigan ma'lumotga — ehtiyotkorlik
     (Provider value o'zgarsa, BARCHA consumer re-render — katta state uchun Redux/Zustand 12.2)

useContextprops drilling muammosini hal qiladi. Props drilling — ma'lumotni (masalan theme) faqat chuqurdagi bir komponentga yetkazish uchun har oraliq qatlamdan qo'lda uzatish (App Page Layout Sidebar Button) — zerikarli, mo'rt (oraliq komponentga keraksiz props), o'zgartirish qiyin. Context buni hal qiladi (markaziy "radio to'lqini"): (1) createContext(default) bilan kontekst yaratasiz (alohida faylda); (2) <Context.Provider value={...}> bilan ma'lumot manbaini yuqorida o'rab qo'yasiz — ostidagi butun daraxt uni o'qiy oladi (React 19'da .Providersiz, to'g'ridan <Context value={...}>); (3) istalgan chuqurlikdagi bola useContext(Context) bilan to'g'ridan oladi (oraliq qatlamlar bilmaydi ham). Qachon Context: yarim-global ma'lumot — theme, til (i18n — 8.30), autentifikatsiya (joriy user), savat. Muhim ogohlantirish: Context props drilling'ni yo'qotadi, lekin Provider'ning value'si o'zgarganda barcha consumer re-render bo'ladi — shuning uchun tez-tez o'zgaradigan katta state uchun Context o'rniga maxsus vositalar (Redux/Zustand — 12.2, 12.5) yoki Context'ni bo'lib ishlatish afzal 11.11-bob.

2.11a. Context — default, ko'p context va performance (split)

text
  DEFAULT QIYMAT — createContext(default) argumenti FAQAT Provider TOPILMAGANDA ishlaydi:
  const ThemeContext = createContext("light");   // Provider yo'q daraxtda  "light"
  //  Provider bilan o'ralgan bo'lsa — default e'tiborga olinmaydi (value ishlatiladi)
  //  createContext(null) + custom hook'da tekshirish — Provider'siz ishlatishni tutadi (Xato 5)

  KO'P CONTEXT — bir ilovada bir nechta mustaqil context (ular ustma-ust o'raladi):
  <AuthProvider>
    <ThemeProvider>
      <App />           {/* App ham auth, ham theme'ni o'qiy oladi */}
    </ThemeProvider>
  </AuthProvider>
   har biri o'z mas'uliyati uchun (auth, theme, til) — aralashtirilmaydi

  PERFORMANCE — CONTEXT SPLIT (bo'lish): value o'zgarsa BARCHA consumer re-render:
   <Ctx value={{ user, theme, cart, setCart }}>  // cart o'zgarsa — user o'quvchilari ham re-render
   Alohida context: <UserCtx> + <ThemeCtx> + <CartCtx>  // faqat kerakli qism re-render
   value'ni useMemo bilan barqarorlashtir 11.6-bob — har render'da yangi obyekt bermaslik

   Tez o'zgaradigan qism (masalan input value) — alohida context yoki state pastroqda
   Katta global state — Redux/Zustand context'dan ko'ra optimallashgan (12.2, 12.5)

Context — default, ko'p context va performance — uchta amaliy nozik nuqta. (1) Default qiymat: createContext(default)ning argumenti faqat komponent daraxtda hech qanday Provider bilan o'ralmagan bo'lsa ishlaydi; Provider bor bo'lsa, uning value'si ishlatiladi va default e'tiborga olinmaydi. Ko'p loyihada createContext(null) qilib, custom hook ichida "Provider yo'qmi?" deb tekshirish afzal (Provider'siz ishlatilsa — aniq xato beradi, Xato 5). (2) Ko'p context: ilovada bir nechta mustaqil context bo'lishi normal (auth, theme, til) — ular Provider'lar sifatida ustma-ust o'raladi; har biri o'z mas'uliyati uchun, aralashtirilmaydi. (3) Performance / context split: Provider'ning value'si o'zgarganda hamma consumer re-render bo'ladi — shuning uchun bog'liq bo'lmagan ma'lumotlarni bitta katta context'ga tiqmang, alohida context'larga bo'ling (UserContext + ThemeContext + CartContext), va value obyektini har render'da yangidan yaratmaslik uchun useMemo bilan barqarorlashtiring 11.6-bob. Tez-tez o'zgaradigan (input kabi) qismni alohida ajratish yoki state'ni pastroqqa tushirish re-render'ni kamaytiradi.

2.12. useRef — DOM elementiga to'g'ridan kirish

text
  useRef — DOM elementiga "ishora" (React'dan tashqari to'g'ridan kirish kerak bo'lganda):

  function SearchInput() {
    const inputRef = useRef(null);              // 1. ref yarat (boshlang'ich null)

    useEffect(() => {
      inputRef.current.focus();                 // 3. DOM metodi (.current — haqiqiy element)
    }, []);                                       //    mount'da fokusni inputga qo'y

    return <input ref={inputRef} />;            // 2. ref'ni elementga ula
  }

  REF + DOM tipik holatlar:
  - .focus() / .blur()        (fokus boshqaruvi)
  - .scrollIntoView()         (elementga skroll)
  - element o'lchovi (.offsetWidth, getBoundingClientRect)
  - <video>/<audio> .play()/.pause(), canvas, 3-tomon kutubxona (chart, map)

   ref.current — render'dan KEYIN to'ladi (DOM mavjud bo'lgach)  useEffect ichida ishlat
   DOM'ni React boshqaradi; ref FAQAT React qila olmaydigan narsaga (fokus, skroll, o'lchov)
   React 19: ref oddiy prop (forwardRef ko'p holda kerak emas — 11.12)

useRef — DOM kirish — React odatda DOM'ni o'zi boshqaradi (deklarativ), lekin ba'zan DOM elementiga to'g'ridan kirish kerak bo'ladi (fokus, skroll, o'lchov, media play) — buning uchun useRef. Uch qadam: (1) const inputRef = useRef(null) (ref obyekt yaratiladi); (2) <input ref={inputRef} /> (ref elementga ulanadi); (3) inputRef.current orqali haqiqiy DOM elementiga kirib, uning metodlarini chaqirasiz (.focus(), .scrollIntoView()). Tipik holatlar: fokus boshqaruvi (.focus()/.blur()), elementga skroll (.scrollIntoView()), o'lchov (.offsetWidth, getBoundingClientRect()), media (<video>.play()), 3-tomon kutubxonalarni DOM'ga ulash (chart, xarita — 8.28). Muhim: ref.current faqat render'dan keyin (DOM mavjud bo'lgach) to'ladi — shuning uchun unga useEffect ichida yoki hodisa handlerida murojaat qiling (render paytida null). DOM'ni asosan React boshqaradi — ref'ni faqat React qila olmaydigan narsaga ishlating (UI'ni ref bilan o'zgartirmang — bu state'ning ishi). React 19'da ref — oddiy prop (forwardRef ko'p holda kerak emas — 11.12).

2.13. useRef — render'siz qiymat saqlash (mutable)

text
  useRef — DOM'dan tashqari: RE-RENDER'SIZ o'zgaradigan qiymat saqlash (cho'ntak daftarchasi)

  useState vs useRef:
  ┌──────────────┬─────────────────────┬──────────────────────────┐
  │              │ useState            │ useRef                   │
  ├──────────────┼─────────────────────┼──────────────────────────┤
  │ o'zgarsa     │ RE-RENDER qiladi    │ re-render qilMAYDI       │
  │ qiymat       │ render'lar orasida  │ render'lar orasida       │
  │              │ saqlanadi           │ saqlanadi                │
  │ o'qish/yozish│ [val, setVal]       │ ref.current (to'g'ridan) │
  │ uchun        │ UI'da ko'rinadigan  │ UI'ga ta'sir qilmaydigan │
  └──────────────┴─────────────────────┴──────────────────────────┘

  TIPIK (render'siz qiymat):
  - interval/timeout ID saqlash (keyin tozalash uchun):
    const idRef = useRef(null);
    idRef.current = setInterval(...);   // saqlaymiz; o'zgarishi re-render keltirmaydi
  - oldingi qiymatni eslab qolish (previous value)
  - "birinchi render'mi?" bayroq; render sonini sanash (UI'ga chiqarmasdan)

   ref.current'ni render PAYTIDA o'qima/yozma (UI bilan sinxron emas)  hodisa/effekt ichida
   Qoida: UI'ga TA'SIR qiladigan  useState; ko'rinmaydigan "yon" qiymat  useRef

useRef — render'siz qiymat saqlashuseRefning ikkinchi vazifasi: DOM'dan tashqari, re-render keltirmasdan o'zgaradigan qiymat saqlash ("cho'ntak daftarchasi"). useState vs useRef: ikkalasi ham qiymatni render'lar orasida saqlaydi, lekin useState o'zgarganda re-render qiladi (UI yangilanadi), useRef esa re-render qilmaydi (ref.currentni o'zgartirish jim — UI'ga ta'sir qilmaydi). Tipik render'siz holatlar: interval/timeout ID'ni saqlash (keyin clearInterval uchun), oldingi qiymatni eslab qolish (previous value), "birinchi render'mi?" bayrog'i, render sonini UI'ga chiqarmasdan sanash. Ikki qoida: (1) ref.currentni render paytida o'qima/yozma (u UI bilan sinxron emas, snapshot kafolatini buzadi) — faqat hodisa handler yoki useEffect ichida; (2) tanlov qoidasi — qiymat o'zgarganda UI yangilanishi kerakmi? Ha useState; yo'q (ko'rinmaydigan "yon" qiymat) useRef. Bu farqni tushunish ikki hookni to'g'ri ishlatishning kaliti.

2.13a. Ref'ni komponentga uzatish — ref prop va forwardRef

text
  MUAMMO: ref oddiy prop kabi bola KOMPONENTGA o'tmaydi (faqat DOM elementga ulanadi):
  <MyInput ref={r} />   // r — MyInput'ning ICHKI <input>'iga qanday yetadi?

  REACT 19 (yangi, sodda) — ref ODDIY PROP:
  function MyInput({ ref, ...props }) {
    return <input ref={ref} {...props} />;   // ref'ni to'g'ridan ichki DOM'ga uzatamiz
  }
  // <MyInput ref={r} />   r.current — ichki <input> DOM elementi

  REACT 18 va oldin — forwardRef bilan o'rash kerak edi:
  const MyInput = forwardRef((props, ref) => {
    return <input ref={ref} {...props} />;   // ref ikkinchi argument sifatida keladi
  });

   Nega kerak: ota komponent bola ichidagi DOM'ga (fokus, skroll) yetishi uchun
   React 19'da forwardRef kerak emas (ref — oddiy prop); eski kodda hali uchraydi (11.12)

Ref'ni komponentga uzatishref oddiy prop kabi ishlamaydi: <MyInput ref={r} /> yozsangiz, r avtomatik MyInput ichidagi <input> DOM'iga yetmaydi (bola — funksiya komponent, DOM emas). Bu ota komponentga bola ichidagi DOM elementiga (fokus qo'yish, skroll) yetish kerak bo'lganda muammo. React 19'da yechim sodda: refoddiy prop, uni function MyInput({ ref }) { return <input ref={ref} /> } deb qabul qilib, ichki DOM'ga uzatasiz. React 18 va undan oldin buning uchun forwardRef bilan komponentni o'rash kerak edi (ref callback'ning ikkinchi argumenti sifatida kelardi). Zamonaviy React 19 loyihada forwardRef odatda kerak emas, lekin eski kodda hali keng uchraydi — shuning uchun ikkalasini ham bilish foydali (batafsil — 11.12).

2.13b. useLayoutEffect va useId

text
  useLayoutEffect — useEffect'ning SINXRON akasi (brauzer chizishdan OLDIN ishlaydi):
  ┌────────────────┬──────────────────────────────┬──────────────────────────┐
  │                │ useEffect                    │ useLayoutEffect          │
  ├────────────────┼──────────────────────────────┼──────────────────────────┤
  │ qachon         │ brauzer chizgandan KEYIN     │ chizishdan OLDIN (sinxron)│
  │ bloklaydimi    │ yo'q (foydalanuvchi ko'radi) │ ha (chizishni kutkazadi) │
  │ qachon kerak   │ deyarli HAMMA holat          │ DOM O'LCHASH  tuzatish   │
  └────────────────┴──────────────────────────────┴──────────────────────────┘

  useLayoutEffect nima uchun: DOM o'lchab (masalan tooltip balandligi), DARHOL joyini
  to'g'rilash kerak bo'lganda — useEffect ishlatilsa, foydalanuvchi "sakrashni" ko'radi:
  useLayoutEffect(() => {
    const { height } = ref.current.getBoundingClientRect();  // DOM'ni o'lcha
    setTooltipTop(-height);                                   // chizishdan OLDIN joyla  sakrash yo'q
  }, []);

   DEFAULT — useEffect; useLayoutEffect faqat "sakrash" (flicker) bo'lsa (u UI'ni sekinlatadi)

  useId — barqaror, noyob ID (label  input bog'lash, SSR mos):
  function Field() {
    const id = useId();                                   // masalan ":r0:"
    return <><label htmlFor={id}>Ism</label><input id={id} /></>;
  }
   useId — LIST key uchun EMAS (u — key emas); a11y (label/input, aria) ID'lari uchun

useLayoutEffect va useId — ikki maxsus hook. useLayoutEffectuseEffectning sinxron akasi: farqi qachon ishlashida. useEffect brauzer ekranga chizgandan keyin ishlaydi (foydalanuvchini bloklamaydi); useLayoutEffect chizishdan oldin, sinxron ishlaydi (brauzer uni kutadi). Deyarli har doim useEffect to'g'ri tanlov. useLayoutEffect faqat bitta holat uchun: DOM'ni o'lchab (masalan tooltip balandligini getBoundingClientRect bilan) darhol joyini to'g'rilash kerak bo'lganda — useEffect ishlatsangiz, foydalanuvchi bir lahza noto'g'ri joyni, keyin "sakrashni" (flicker) ko'radi; useLayoutEffect esa chizishdan oldin to'g'rilaydi. U UI'ni bloklab sekinlatishi mumkin — shuning uchun default useEffect, useLayoutEffectni faqat vizual sakrash muammosida. useId — barqaror, noyob identifikator generatsiya qiladi (htmlFor id bog'lash, aria-* atributlari uchun), va server rendering (SSR) bilan mos (server va klient bir xil ID beradi). useId — ro'yxat (list) key'lari uchun emas (buni ma'lumotdan oling — 11.3); u faqat qulaylik (a11y) ID'lari uchun.

2.13c. Class hayot sikli hook mapping

text
  ESKI class metodi                YANGI hook ekvivalenti
  ┌────────────────────────────┬──────────────────────────────────────────────┐
  │ componentDidMount()        │ useEffect(() => {...}, [])                     │
  │ componentDidUpdate()       │ useEffect(() => {...}, [dep])   (dep o'zgarsa) │
  │ componentWillUnmount()     │ useEffect(() => { return () => {...} }, [])   │
  │ this.state / setState      │ useState / useReducer 11.6-bob                  │
  │ this.instanceVar (render'siz)│ useRef 2.13-bob                                │
  │ shouldComponentUpdate      │ React.memo + useMemo/useCallback 11.11-bob       │
  └────────────────────────────┴──────────────────────────────────────────────┘

   Bir useEffect = mount + update + unmount BIRGA (class'da 3 ta metod edi — 2.1)
   "Sikl metodi"dek emas, "sinxronlash"dek o'yla 2.8-bob — mapping faqat migratsiya uchun

Class hayot sikli hook mapping — eski class kodni hooklarga ko'chirayotganingizda foydali xarita: componentDidMount useEffect(fn, []); componentDidUpdate useEffect(fn, [dep]) (bog'liqlik o'zgarganda); componentWillUnmount useEffectning cleanup funksiyasi (return () => {...}); this.state/setState useState/useReducer 11.6-bob; this ustidagi render'siz o'zgaruvchi useRef 2.13-bob; shouldComponentUpdate optimizatsiyasi React.memo + useMemo/useCallback 11.11-bob. Muhim ogohlantirish: bu jadval faqat migratsiyani tushunish uchun — useEffectni haqiqatan tushunishda uni "hayot sikli metodi"dek emas, sinxronlashdek 2.8-bob qabul qiling. Bitta useEffect mount + update + unmount mantiqini bir joyda birlashtiradi (class'da uch alohida metod edi — 2.1) — bu hooklar sodaligining asosiy sababi.

2.14. Hooklar xulosasi — qaysi birini qachon

text
  ┌─────────────┬──────────────────────────────────────────────────────┐
  │ Hook        │ Qachon ishlatish                                       │
  ├─────────────┼──────────────────────────────────────────────────────┤
  │ useState    │ UI'ga ta'sir qiladigan o'zgaradigan ma'lumot 11.4-bob    │
  │ useEffect   │ tashqi tizim bilan sinxronlash (fetch, taymer, obuna)  │
  │ useContext  │ yarim-global ma'lumot (theme, auth) — drilling'siz     │
  │ useRef      │ DOM kirish YOKI render'siz "yon" qiymat                │
  │ useLayoutEffect│ DOM o'lchash  chizishdan OLDIN tuzatish (2.13b)     │
  │ useId       │ barqaror noyob ID (label/input, a11y — 2.13b)          │
  │ useReducer  │ murakkab/bog'liq state mantiqi 11.6-bob                  │
  │ useMemo     │ qimmat hisobni keshlash (11.6, 11.11)                  │
  │ useCallback │ funksiyani keshlash (11.6, 11.11)                       │
  │ custom hook │ mantiqni qayta ishlatish 11.7-bob                       │
  └─────────────┴──────────────────────────────────────────────────────┘

   Avval ENG SODDA yechim (useState + render'da hisob)  murakkablashsa hook qo'sh
   Hookni "shunchaki" ishlatma — har birining aniq sababi bo'lsin (effekt KERAK EMAS — 2.10)

Hooklar xulosasi — qaysi hookni qachon ishlatish bo'yicha yo'l xaritasi. useState — UI'ga ta'sir qiladigan o'zgaradigan ma'lumot 11.4-bob. useEffect — tashqi tizim bilan sinxronlash (fetch, taymer, obuna — faqat haqiqiy side effect, 2.10). useContext — yarim-global ma'lumot (theme, auth) props drilling'siz. useRef — DOM kirish yoki render'siz "yon" qiymat. Va keyingi boblarda: useReducer (murakkab/bog'liq state — 11.6), useMemo/useCallback (keshlash, performance — 11.6, 11.11), custom hook (mantiqni qayta ishlatish — 11.7). Ikki tamoyil: (1) har doim eng sodda yechimdan boshla (oddiy useState + render'da hisoblash — 11.4: 2.14) va faqat zarurat tug'ilganda murakkabroq hook qo'sh; (2) hookni "shunchaki, hamma ishlatadi" deb ishlatma — har birining aniq sababi bo'lsin (ayniqsa useEffect — ko'p hollarda kerak emas — 2.10). To'g'ri hook tanlash — toza, tez, xatosiz React kodning asosi.


3. Sintaksis — tez ma'lumotnoma

text
EFFECT 2.5-bob:     useEffect(() => { ...; return () => {cleanup} }, [deps])
DEPS 2.6-bob:       (yo'q) har render | [] bir marta(mount) | [a,b] a/b o'zgarganda
CLEANUP 2.7-bob:    return () => { clearInterval(id) / unsubscribe() / abort() }
FETCH (Misol 3):  useEffect(() => { let active=true; fetch().then(d => active && setData(d));
                                    return () => { active=false } }, [id])
CONTEXT 2.11-bob:   const Ctx=createContext(def) | <Ctx.Provider value={x}> | useContext(Ctx)
REF DOM 2.12-bob:   const r=useRef(null) | <input ref={r}/> | r.current.focus()
REF QIYMAT 2.13-bob:const r=useRef(0) | r.current = 5   // re-render YO'Q
UPDATER 2.9-bob:    setInterval(() => setX(prev => prev+1), 1000)  // stale closure'dan qochish
LAZY INIT(2.3a):  useState(() => qimmatHisob())   // FAQAT mount'da; useState(fn()) EMAS
ASYNC (2.6a):     useEffect(() => { async function f(){...} f(); return ()=>{} }, [dep])
LAYOUT (2.13b):   useLayoutEffect(() => { o'lcha; joyla }, [])   // chizishdan OLDIN (flicker yo'q)
useId (2.13b):    const id = useId()  | <label htmlFor={id}/> <input id={id}/>
REF PROP (2.13a): function In({ref}){ return <input ref={ref}/> }  // R19; R18: forwardRef

4. Batafsil kod namunalari

Misol 1 — useEffect: mount'da bir marta (2.5, 2.6)

jsx
import { useState, useEffect } from "react";

function Welcome() {
  const [message, setMessage] = useState("Yuklanmoqda...");

  useEffect(() => {
    // Bu FAQAT mount'da (birinchi render'dan keyin) ishlaydi ([] — 2.6)
    console.log("Komponent paydo bo'ldi");
    setMessage("Xush kelibsiz!");
  }, []);                                    // bo'sh deps  bir marta

  return <h1>{message}</h1>;
}
//  [] — boshlang'ich sozlash/yuklash uchun; har render'da emas (2.6)

Misol 2 — useEffect: dependency o'zgarganda (2.6)

jsx
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    console.log("userId o'zgardi:", userId);
    fetchUser(userId).then(setUser);          // userId o'zgarganda qayta yukla
  }, [userId]);                                //  userId deps'da — o'zgarsa effekt qayta ishlaydi

  if (!user) return <p>Yuklanmoqda...</p>;     // shartli render (11.4: 2.12)
  return <h2>{user.name}</h2>;
}
//  userId effekt ichida ishlatildi  deps'da BO'LISHI shart (exhaustive-deps — 2.6)

Misol 3 — Data fetching: loading/error/data + cleanup (2.6, 2.7)

jsx
function Products() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let ignore = false;                        //  "race condition"dan himoya (eski javobni rad et)
    setLoading(true);
    setError(null);

    fetch("https://api.example.com/products")
      .then(res => {
        if (!res.ok) throw new Error("Server xatosi");
        return res.json();
      })
      .then(json => { if (!ignore) setData(json); })  // faqat hali aktual bo'lsa
      .catch(err => { if (!ignore) setError(err.message); })
      .finally(() => { if (!ignore) setLoading(false); });

    return () => { ignore = true; };           // cleanup: komponent yo'qolsa/qayta yuklansa — eskini rad et
  }, []);                                        // mount'da bir marta

  if (loading) return <Spinner />;             // 3 holat (11.4: 2.12)
  if (error) return <p className="error">{error}</p>;
  return <ul>{data.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
}
//  "ignore" bayrog'i — tez almashgan so'rovlarda eski javob yangisini bosib ketmasligi uchun
//    (haqiqiy loyihada TanStack Query buni avtomatik qiladi — 12.4)

Misol 4 — Cleanup: taymer (interval — 2.7, 2.9)

jsx
function Clock() {
  const [time, setTime] = useState(new Date());

  useEffect(() => {
    const id = setInterval(() => {
      setTime(new Date());                     // har soniyada yangila
      //  Agar setTime(time) bo'lsa — stale closure (time qotgan). Bu yerda yangi obyekt — muammosiz
    }, 1000);

    return () => clearInterval(id);            //  komponent yo'qolsa — taymerni O'CHIR (leak'dan saqlanish — 2.7)
  }, []);                                        // bir marta o'rnat

  return <p>Vaqt: {time.toLocaleTimeString()}</p>;
}

Misol 5 — Cleanup: event listener / subscription (2.7)

jsx
function WindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    function handleResize() { setWidth(window.innerWidth); }
    window.addEventListener("resize", handleResize);   // obuna

    return () => window.removeEventListener("resize", handleResize); //  cleanup — obunani bekor qil
  }, []);

  return <p>Oyna kengligi: {width}px</p>;
}
//  removeEventListener'da AYNAN o'sha funksiya (handleResize) berilishi shart (anonim emas)

Misol 6 — DOM bilan ishlash: document.title sinxron (2.4, 2.8)

jsx
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Bosildi: ${count} marta`;   // DOM (sahifa sarlavhasi)ni state bilan sinxronla
  }, [count]);                                       // count o'zgarganda yangila (sinxronlash — 2.8)

  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
//  Sarlavha — tashqi tizim (document); useEffect uni count bilan SINXRON ushlaydi (2.8)

Misol 7 — Infinite loop xatosi va tuzatish (2.9)

jsx
function BuggyVsFixed({ userId }) {
  const [user, setUser] = useState(null);

  //  INFINITE LOOP — har render'da yangi obyekt (yangi havola  "o'zgargan"  effekt  render  ...)
  // const config = { id: userId };
  // useEffect(() => { fetchUser(config).then(setUser); }, [config]);

  //  TO'G'RI — primitiv dependency (userId — o'zgargandagina effekt)
  useEffect(() => {
    const config = { id: userId };              // obyektni effekt ICHIDA yarat (deps'da emas)
    fetchUser(config).then(setUser);
  }, [userId]);                                  // primitiv dep — barqaror taqqoslash (2.9)

  return <div>{user?.name}</div>;
}

Misol 8 — Stale closure va updater bilan tuzatish (2.9)

jsx
function AutoCounter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      //  setCount(count + 1) — count MOUNT'dagidek 0 da QOTGAN  har doim 01 (stale closure)
      setCount(prev => prev + 1);              //  updater — prev har doim eng yangi (11.4: 2.6)
    }, 1000);
    return () => clearInterval(id);
  }, []);                                        // [] — effekt bir marta yaratiladi (count qotardi)

  return <h1>{count}</h1>;                       // 0, 1, 2, 3... to'g'ri sanaydi
}
//  Stale closure: effekt [] bilan 1 marta yaratiladi, count o'sha render snapshot'ida.
//    Yechim — updater (prev =>), u React'dan eng yangi qiymatni oladi (deps'ga count qo'shmasdan)

Misol 9 — useEffect KERAK EMAS: derived state (2.10)

jsx
function Cart({ items }) {
  //  KERAK EMAS — total'ni effekt bilan hisoblash (ortiqcha state + render):
  // const [total, setTotal] = useState(0);
  // useEffect(() => { setTotal(items.reduce((s, i) => s + i.price, 0)); }, [items]);

  //  TO'G'RI — render PAYTIDA hisobla (state emas — 11.4: 2.14, 2.10):
  const total = items.reduce((sum, item) => sum + item.price, 0);   // har render'da qayta hisob
  const count = items.length;

  return <p>{count} ta mahsulot — Jami: {total} so'm</p>;
}
//  items'dan KELIB CHIQADIgan narsa — state EMAS, effekt EMAS — to'g'ridan hisobla (2.10)

Misol 10 — useContext: Theme provider (2.11)

jsx
// src/context/ThemeContext.jsx
import { createContext, useContext, useState } from "react";

const ThemeContext = createContext();          // kontekst yaratamiz

export function ThemeProvider({ children }) {  // o'rovchi (provider) komponent
  const [theme, setTheme] = useState("light");
  const toggle = () => setTheme(t => (t === "light" ? "dark" : "light"));
  return (
    <ThemeContext.Provider value={{ theme, toggle }}>  {/* React 19: <ThemeContext value={...}> */}
      {children}
    </ThemeContext.Provider>
  );
}

export const useTheme = () => useContext(ThemeContext);  // qulay custom hook 11.7-bob

// Ishlatish — istalgan chuqurlikdagi bola (props drilling YO'Q):
function ThemeButton() {
  const { theme, toggle } = useTheme();         // to'g'ridan oladi (oraliq qatlamlar bilmaydi)
  return <button onClick={toggle}>Mavzu: {theme}</button>;
}
// main.jsx: <ThemeProvider><App /></ThemeProvider>   butun App theme'ni o'qiy oladi

Misol 11 — useContext: Auth context (2.11)

jsx
const AuthContext = createContext();

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);

  const login = async (email, password) => {
    const data = await api.login(email, password);  // 12.4
    setUser(data.user);
  };
  const logout = () => setUser(null);

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}
export const useAuth = () => useContext(AuthContext);

// Istalgan komponentda:
function Navbar() {
  const { user, logout } = useAuth();
  return user
    ? <button onClick={logout}>Chiqish ({user.name})</button>   // shartli (11.4: 2.12)
    : <a href="/login">Kirish</a>;
}
//  Auth — klassik Context holati (butun ilovaga kerak, kam o'zgaradigan)

Misol 12 — useRef: DOM elementga fokus (2.12)

jsx
function SearchForm() {
  const inputRef = useRef(null);               // ref yaratamiz

  useEffect(() => {
    inputRef.current.focus();                  // mount'da fokusni inputga qo'y (.current — DOM)
  }, []);

  function clearAndFocus() {
    inputRef.current.value = "";               // DOM'ni to'g'ridan (faqat imperativ holatda)
    inputRef.current.focus();
  }

  return (
    <form>
      <input ref={inputRef} placeholder="Qidirish..." />   {/* ref'ni elementga ulaymiz */}
      <button type="button" onClick={clearAndFocus}>Tozala</button>
    </form>
  );
}
//  Fokus — React deklarativ qila olmaydi  ref bilan imperativ (2.12)

Misol 13 — useRef: oldingi qiymat va interval ID (2.13)

jsx
function PreviousValue({ count }) {
  const prevRef = useRef();                     // render'siz qiymat saqlash

  useEffect(() => {
    prevRef.current = count;                    // har render'dan keyin joriy count'ni eslab qol
  }, [count]);                                   // (re-render keltirmaydi — 2.13)

  const prev = prevRef.current;                 // oldingi qiymat (effekt undan oldin o'qildi)
  return <p>Hozir: {count}, oldin: {prev ?? "yo'q"}</p>;
}

function Stopwatch() {
  const [seconds, setSeconds] = useState(0);
  const intervalRef = useRef(null);             // interval ID'ni render'siz saqlaymiz

  const start = () => {
    if (intervalRef.current) return;            // allaqachon ishlayaptimi?
    intervalRef.current = setInterval(() => setSeconds(s => s + 1), 1000);
  };
  const stop = () => {
    clearInterval(intervalRef.current);
    intervalRef.current = null;                 // o'zgarishi re-render keltirmaydi (2.13)
  };

  return (
    <div>
      <p>{seconds}s</p>
      <button onClick={start}>Boshlash</button>
      <button onClick={stop}>To'xtatish</button>
    </div>
  );
}

Misol 14 — Hammasi birga: qidiruv + debounce (useState + useEffect + useRef + cleanup)

jsx
function LiveSearch() {
  const [query, setQuery] = useState("");
  const [results, setResults] = useState([]);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (!query.trim()) { setResults([]); return; }   // bo'sh bo'lsa — qidirmaymiz

    setLoading(true);
    const controller = new AbortController();         // fetchni bekor qilish uchun (2.7)

    // DEBOUNCE — foydalanuvchi yozishni to'xtatgandan 400ms keyin qidir (har harfda emas)
    const timer = setTimeout(() => {
      fetch(`/api/search?q=${query}`, { signal: controller.signal })
        .then(r => r.json())
        .then(data => { setResults(data); setLoading(false); })
        .catch(err => { if (err.name !== "AbortError") setLoading(false); });
    }, 400);

    return () => {                                    //  cleanup: query o'zgarsa — eski timer va fetchni bekor qil
      clearTimeout(timer);                            // eski debounce taymerni o'chir
      controller.abort();                             // eski so'rovni bekor qil (2.7)
    };
  }, [query]);                                        // query o'zgarganda qayta sinxronlash (2.8)

  return (
    <div>
      <input value={query} onChange={e => setQuery(e.target.value)} placeholder="Qidirish..." />
      {loading && <small>Qidirilmoqda...</small>}
      <ul>{results.map(r => <li key={r.id}>{r.title}</li>)}</ul>
    </div>
  );
}
//  Bu naqsh — debounce + abort + cleanup — real qidiruvning standarti (12.4'da Query soddalashtiradi)

5. To'g'ri va noto'g'ri holatlar

1) Hook joylashuvi

text
 if (x) { useState(...) }  /  for(...) { useEffect(...) }  (shart/tsikl ichida — 2.2)
 komponent tepasida, shartsiz; shartni hook ICHIDA qo'y

2) Dependency array

text
 useEffect(() => { fetch(id) }, [])  (id ishlatildi, deps'da yo'q — eski id — 2.6)
 useEffect(() => { fetch(id) }, [id])  (exhaustive-deps)

3) Cleanup

text
 setInterval/addEventListener — cleanup yo'q (memory leak — 2.7)
 return () => clearInterval(id) / removeEventListener(...)

4) Stale closure

text
 setInterval(() => setCount(count + 1), 1000)  (count qotgan — 2.9)
 setInterval(() => setCount(c => c + 1), 1000)  (updater)

5) Keraksiz effekt

text
 useEffect(() => setFull(a + " " + b), [a, b])  (derived state — 2.10)
 const full = a + " " + b  (render'da hisobla)

6) Object dependency

text
 const opt = {id}; useEffect(..., [opt])  (har render yangi havola  tsikl — 2.9)
 [id]  (primitiv) yoki obyektni effekt ichida yarat / useMemo (11.6)

7) useRef vs useState

text
 UI'da ko'rinadigan qiymat useRef'da (o'zgarsa ekran yangilanmaydi — 2.13)
 UI'ga ta'sir  useState; render'siz "yon" qiymat  useRef

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — React Hook useEffect has a missing dependency: 'x'

Sababi: effekt ichida x ishlatildi, lekin deps'da yo'q 2.6-bob. Yechimi: xni deps'ga qo'sh; agar tsikl bo'lsa — sababi object/function dep (Misol 7) yoki effekt kerak emas 2.10-bob. Deps'ni qo'lda "aldama".

Xato 2 — Sahifa qotib qoladi / Maximum update depth exceeded

Sababi: infinite loop — effekt state'ni yangilab, o'sha state deps'da (yoki object dep — 2.9). Yechimi: deps'ni to'g'rila (primitiv), yoki effektni umuman olib tashla (derived — 2.10).

Xato 3 — Cannot read properties of null (reading 'focus')

Sababi: ref.current hali null (render paytida yoki element ulanmagan). Yechimi: useEffect ichida ishlat (DOM tayyor); ref.current?.focus() 2.12-bob.

Xato 4 — Taymer/listener komponent yo'qolgach ham ishlayveradi

Sababi: cleanup yo'q 2.7-bob. Yechimi: return () => clearInterval(id) / removeEventListener(...).

Xato 5 — useContext undefined qaytaradi

Sababi: komponent Provider ICHIDA emas (daraxtda yuqorida Provider yo'q — 2.11). Yechimi: ildizda (main.jsx/App) <Provider> bilan o'ra; custom hook'da tekshir (if (!ctx) throw).

Xato 6 — State eski qiymatda qotgan (setInterval/setTimeout ichida)

Sababi: stale closure 2.9-bob. Yechimi: updater funksiya (setX(prev => ...) — Misol 8), yoki kerakli qiymatni useRefda sakla.

Xato 7 — StrictMode'da effekt ikki marta ishlaydi (dev)

Sababi: bu ataylab (cleanup'ni tekshirish — 11.2: 2.11). Yechimi: to'g'ri cleanup yoz — shunda ikki marta ishlash zararsiz; bu xato emas (production'da bir marta).


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • State 11.4-bob: useState — birinchi hook; updater (2.9 stale closure yechimi).
  • useReducer/useMemo/useCallback 11.6-bob: murakkab state va keshlash hooklari.
  • Custom hooks 11.7-bob: bu hooklarni birlashtirib o'z hookingni yozasiz (Misol 10 useTheme).
  • Data fetching 12.4-bob: useEffect+fetch TanStack Query buni soddalashtiradi (race, cache avtomatik).
  • Context API 12.1-bob: useContext chuqur kengaytmasi; Redux 12.2-bob alternativasi.
  • Forma 11.10-bob: controlled + effekt; React Hook Form effekt og'rig'ini kamaytiradi.
  • WebSocket 5.13-bob: useEffect + cleanup — obuna/uzilish naqshi.
  • Performance 11.11-bob: keraksiz effekt/re-render; object dep muammosi 2.9-bob.

8. Eng yaxshi amaliyotlar (best practices)

  • Rules of Hooks'ga rioya (tepada, shartsiz; ESLint plugin yoq — 2.2, 15.3).
  • exhaustive-deps'ga quloq sol (deps'ni qo'lda aldama — 2.6, Xato 1).
  • Har band qiluvchi effektga cleanup (taymer, listener, obuna, fetch — 2.7).
  • Updater funksiya (asinxron/taymer ichida stale closure'dan qoch — 2.9).
  • "Effekt kerakmi?" deb so'ra (derived state'ni render'da hisobla; hodisani handler'da — 2.10).
  • Object/function dep'dan ehtiyot (primitiv dep yoki useMemo — 2.9, 11.6).
  • Sinxronlash modelida o'yla (lifecycle emas — "nimani sinxron ushlaydi" — 2.8).
  • useContext yarim-global uchun (theme/auth; tez-tez o'zgaradigan katta state — Redux 12.2).
  • useRef to'g'ri tanla (DOM yoki render'siz qiymat; UI'ga ta'sir useState — 2.13).
  • Fetch'ni Query'ga ko'chir (real loyihada useEffect+fetch o'rniga TanStack Query — 12.4).

9. Amaliy loyiha: "Ob-havo va Vaqt Dashboard"

Bu loyiha barcha to'rt hookni birga ishlatadi — real API, taymer, global mavzu, DOM fokus.

Maqsad

Shahar ob-havosini API'dan oladigan, jonli soat ko'rsatadigan, mavzu (light/dark) almashtiradigan dashboard yarat.

Talablar (requirements)

  1. Jonli soat: useEffect + setInterval + cleanup; har soniyada yangilansin (Misol 4).
  2. Ob-havo fetch: shahar input'iga qarab API'dan ma'lumot (loading/error/data — Misol 3).
  3. Debounce: shahar yozishni to'xtatgandan keyin qidir (setTimeout + cleanup — Misol 14).
  4. Race himoyasi: tez almashgan so'rovlarda eski javob yangisini bosmasin (ignore/AbortController — Misol 3, 14).
  5. Theme Context: light/dark mavzu, useContext bilan butun dashboard'ga (Misol 10).
  6. Auto-focus: sahifa ochilganda shahar input'iga fokus (useRef + useEffect — Misol 12).
  7. Oxirgi qidiruvlar: so'nggi 5 qidiruvni ko'rsat (massiv state — 11.4: 2.9).
  8. document.title: joriy shahar nomini sahifa sarlavhasiga sinxronla (Misol 6).
  9. Cleanup to'liq: har taymer/fetch/listener tozalansin (memory leak yo'q — 2.7).
  10. "Effekt kerakmi?" tekshir: hosilangan qiymat (masalan formatlangan harorat)ni render'da hisobla, effektda emas 2.10-bob.

Maslahatlar (hint)

  • API: ochiq ob-havo API (masalan open-meteo — kalit talab qilmaydi) yoki mock ma'lumot.
  • useEffect deps'ni to'g'ri qo'y: soat [], ob-havo [city].
  • Debounce + AbortController + cleanup — Misol 14 naqshini ishlat.
  • Theme'ni alohida ThemeProvider + useTheme hook qil (Misol 10) — main.jsxda o'ra.
  • Stale closure'dan ehtiyot bo'l: taymerda setX(prev => ...) (Misol 8).
  • ESLint ogohlantirishlariga quloq sol (exhaustive-deps) — ular to'g'ri yo'lni ko'rsatadi.

"Tayyor" mezonlari (acceptance criteria)

  • Jonli soat ishlaydi va cleanup bor (komponent yo'qolsa taymer to'xtaydi).
  • Ob-havo fetch: loading/error/data uch holati to'g'ri.
  • Debounce ishlaydi (har harfda emas, to'xtagach qidiradi).
  • Race condition yo'q (eski javob yangisini bosmaydi).
  • Theme Context butun dashboard'ga ta'sir qiladi (drilling yo'q).
  • Input mount'da avtomatik fokuslanadi.
  • So'nggi qidiruvlar ro'yxati ishlaydi.
  • document.title shahar bilan sinxron.
  • Hech qanday memory leak yo'q (barcha cleanup mavjud).
  • Hosilangan qiymatlar render'da hisoblangan (keraksiz effekt yo'q).

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda React hooklarini chuqur o'rgandik:

  • Hook nima (class'dan o'tish — 2.1); Rules of Hooks (nega tepada, shartsiz — chaqiruv tartibi — 2.2); ko'p useState 2.3-bob, lazy init va funksional update (2.3a).
  • Side effect (pure render vs effect — 2.4); useEffect anatomiyasi 2.5-bob, dependency array (yo'q/[]/[deps] — 2.6), effekt ichida async (2.6a), cleanup (resurs bo'shatish — 2.7), sinxronlash modeli (lifecycle emas — 2.8).
  • Tuzoqlar (infinite loop, object dep, stale closure — 2.9); qachon effekt KERAK EMAS (derived state, hodisa — 2.10).
  • useContext (props drilling'siz — 2.11; default/ko'p context/split — 2.11a); useRef (DOM kirish — 2.12, render'siz qiymat — 2.13, ref prop/forwardRef — 2.13a); useLayoutEffect/useId (2.13b); class hook mapping (2.13c); hooklar xulosasi 2.14-bob.

Endi siz real ilova qura olasiz: serverdan ma'lumot (useEffect+fetch), global state (useContext), DOM kirish va render'siz qiymat (useRef) — va eng muhimi, eng keng tuzoqlardan (stale closure, infinite loop, keraksiz effekt) qochishni bilasiz.

Keyingi bob — 11.6-bob: useMemo, useCallback, useReducer. Hooklar bilimini yakunlaymiz: useReducer (murakkab, bog'liq state mantiqi — useStatening kuchliroq ukasi, Redux falsafasiga ko'prik — 12.2), useMemo (qimmat hisobni keshlash — ortiqcha qayta hisoblashni to'xtatish), useCallback (funksiyani keshlash — bu bobdagi object/function dependency muammosini hal qiladi — 2.9). Bu hooklar — performance optimizatsiya 11.11-bob va katta ilova arxitekturasining poydevori.


Foydalanilgan rasmiy/ishonchli manbalar

  • React rasmiy hujjati (react.dev) — "Synchronizing with Effects", "You Might Not Need an Effect", "Lifecycle of Reactive Effects", "Removing Effect Dependencies"
  • react.dev — useState, useEffect, useContext, useRef API reference; "Rules of Hooks", "Manipulating the DOM with Refs", "Referencing Values with Refs"
  • react.dev — useState: lazy initializer va updater funksiya ("Passing an updater function", "avoiding recreating the initial state")
  • react.dev — useLayoutEffect, useId API reference; "Separating Events from Effects", "State as a Snapshot"
  • react.dev — "Passing Data Deeply with Context", "Scaling Up with Reducer and Context", "Reusing Logic with Custom Hooks"
  • react.dev — React 19 release notes: <Context> as provider, ref as a prop; forwardRef (React 18 API)
  • MDN — setInterval/clearInterval, AbortController, addEventListener, Element.getBoundingClientRect()

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
11.5-bob: Hooks — useState, useEffect, useContext, useRef — Wisar