WisarWisar
Dasturlash kitobi/11-QISM — React41 daqiqa

11.4-bob: State, hodisalar, shartli render, ro'yxatlar va keys

11-QISM — Frontend: React · 4-mavzu


1. Kirish va motivatsiya

11.2-bobda komponent va props'ni, 11.3-bobda Vite loyihasini o'rgandik — lekin ilovamiz hali jonsiz. Foydalanuvchi tugmani bossa, matn yozsa, hech narsa o'zgarmaydi. Sababi oddiy: komponentlarimizda xotira yo'q. Ular faqat props orqali kelgan statik ma'lumotni ko'rsatadi, xolos. Endi React'ning eng sehrli, eng markaziy qismiga — statega — o'tamiz. Aynan shu bobda 11.1-bobdagi butun og'riq (har o'zgarishda qo'lda render() chaqirish, UI va ma'lumotni qo'lda sinxronlash) butunlay yo'qoladi, va UI = f(state) formulasi jonlanadi.

State — komponentning "xotirasi": vaqt o'tishi bilan o'zgaradigan, va o'zgarganda UI'ni avtomatik yangilaydigan ma'lumot. Tugma necha marta bosilgani, formadagi matn, modal ochiqmi, ro'yxatdagi elementlar — bularning hammasi state. React'ning asosiy va'dasi shu: siz faqat state'ni o'zgartirasiz, React UI'ni o'zi yangilaydi (DOM'ga qo'lda teginmaysiz, render() chaqirmaysiz, qaysi joyni yangilashni eslab qolmaysiz). Lekin bu sehr ortida aniq qoidalar bor — va aynan shu qoidalarni chuqur tushunmaslik junior dasturchilarning eng katta xatolar manbai. Shuning uchun bu bobni biz odatdagidan ham batafsilroq, har bir holat uchun alohida kod bilan yozamiz.

Bu bob to'rt katta mavzuni qamraydi: State (useState to'liq anatomiyasi, state — snapshot ekani, asinxron/batched yangilanish, updater funksiya, immutability — obyekt va massivni to'g'ri yangilash), Hodisalar (event handlers, argument uzatish, synthetic events, controlled inputs — forma asoslari), Shartli render (if, ternary, &&, element o'zgaruvchi va tuzoqlari), va Ro'yxatlar + key (map, key chuqur — nega kerak, nega index xato), hamda lifting state up (state'ni komponentlar o'rtasida ulashish). Bundan tashqari, senior bo'lish uchun shart bo'lgan tushunchalar — state snapshot modeli, batching, lazy initial state, immutability'ning chuqur sabablari — ham qamraladi.

O'xshatish: State — bu komponentning fotosurati va xotira daftarchasi birgalikda. Tasavvur qil: har "render" — bu komponentning bir lahzalik fotosurati (snapshot). Fotosuratda state qiymati qotib turadi (o'sha lahzada nima bo'lsa, shu). Siz state'ni o'zgartirganda — eski suratni tahrirlamaysiz, balki React'dan yangi surat olishini so'raysiz (re-render). React yangi qiymat bilan komponentni qaytadan "suratga oladi". Mana shuning uchun React'da count = count + 1 deb yozmaysiz (eski suratni o'zgartirib bo'lmaydi) — setCount(count + 1) deb yangi surat buyurtma qilasiz. Va daftarcha (state) — React'ning qo'lida saqlanadi: komponent qayta "tug'ilganda" (re-render), React unga eski daftarchani qaytarib beradi ("oldingi qiymating shu edi"). Bu model — useStatening butun xatti-harakatini izohlaydi.

Nega muhim?

  • React'ning yuragi — state'siz interaktiv UI yo'q; har tugma, forma, ro'yxat — state.
  • Eng ko'p xato shu yerda — snapshot, immutability, batching tushunilmasa — "nega yangilanmayapti?" degan tuzoqlarga tushasiz.
  • Forma va ma'lumot — controlled inputs (11.10 RHF), API ma'lumoti 12.4-bob — hammasi state ustiga quriladi.
  • Deklarativ tafakkurUI = f(state) ni amalda his qilish — barcha keyingi boblarning poydevori.

2. Nazariya — chuqur tushuntirish

2.1. State nima va nega oddiy o'zgaruvchi yetmaydi

text
  MUAMMO: nega oddiy o'zgaruvchi (let count = 0) React'da ishlamaydi?

  function Counter() {
    let count = 0;                         //  oddiy o'zgaruvchi
    return <button onClick={() => {
      count = count + 1;                   // o'zgaradi-yu...
      console.log(count);                  // konsolda 1, 2, 3... (o'zgaryapti)
    }}>{count}</button>;                   // ...lekin EKRAN o'zgarmaydi (0 qoladi)
  }

  2 SABAB:
  1. RE-RENDER YO'Q — oddiy o'zgaruvchini o'zgartirish React'ni "xabardor" qilmaydi
     (React UI'ni qachon yangilashni bilmaydi  ekran eski qoladi)
  2. XOTIRA YO'Q — komponent qayta render bo'lsa, funksiya BOSHIDAN ishlaydi
      let count = 0 yana 0 ga "tiklanadi" (oldingi qiymat yo'qoladi — 11.2: 2.2)

  YECHIM — useState:
  const [count, setCount] = useState(0);   //  React xotirada saqlaydi + re-render qiladi

State — komponentning vaqt o'tishi bilan o'zgaradigan va o'zgarganda UI'ni yangilaydigan ma'lumoti. Nega oddiy o'zgaruvchi (let count = 0) yetmaydi? Ikki sabab: (1) re-render yo'q — oddiy o'zgaruvchini o'zgartirsangiz, React buni bilmaydi, shuning uchun UI'ni yangilamaydi (ekran eski qoladi — konsolda qiymat o'zgarsa ham); (2) xotira yo'q — komponent qayta render bo'lganda funksiya boshidan ishlaydi (11.2: 2.2), shuning uchun let count = 0 yana 0 ga tiklanadi (oldingi qiymat yo'qoladi). useState ikkala muammoni hal qiladi: React qiymatni o'z xotirasida (komponent renderlari orasida) saqlaydi, va state o'zgarganda komponentni qayta render qiladi. Mana shuning uchun React'da xotira kerak bo'lgan har qanday ma'lumot — useState (yoki boshqa hook) orqali saqlanadi, oddiy o'zgaruvchi orqali emas. Oddiy o'zgaruvchi faqat bitta render ichida vaqtincha hisob-kitob uchun ishlatiladi.

2.2. useState anatomiyasi — to'liq tahlil

text
  const [count, setCount] = useState(0);
  //     │       │                    │
  //     │       │                    └─ boshlang'ich qiymat (faqat BIRINCHI render'da)
  //     │       └─ YANGILOVCHI funksiya (state'ni o'zgartiradi + re-render)
  //     └─ joriy QIYMAT (shu render'dagi state)

  useState QAYTARADI: [qiymat, yangilovchiFunksiya]  (massiv — destructuring bilan olamiz — 2.8 JS)

  NOMLASH KONVENSIYASI: [x, setX] — yangilovchi "set" + bosh harf
  const [name, setName] = useState("");          // string
  const [age, setAge] = useState(0);             // number
  const [isOpen, setIsOpen] = useState(false);   // boolean
  const [user, setUser] = useState(null);        // obyekt (boshlang'ich null)
  const [items, setItems] = useState([]);        // massiv (boshlang'ich bo'sh)

   useState — "hook" (React funksiyasi); FAQAT komponent ICHIDA, TEPADA chaqiriladi (11.5: Rules)
   boshlang'ich qiymat FAQAT birinchi render'da ishlatiladi (keyin e'tiborsiz)

useState — eng asosiy React hook'i; u state e'lon qiladi va massiv qaytaradi: [joriyQiymat, yangilovchiFunksiya]. Destructuring bilan ikkisini olamiz (2.8 JS): const [count, setCount] = useState(0). Uch element: count (shu render'dagi joriy qiymat), setCount (state'ni o'zgartiradigan va re-render keltiradigan funksiya), useState(0) dagi 0 (boshlang'ich qiymat — faqat birinchi render'da ishlatiladi, keyingi renderlarda e'tiborsiz qoldiriladi). Nomlash konvensiyasi: [x, setX] (yangilovchi "set" prefiksi bilan). Boshlang'ich qiymat har qanday tur bo'lishi mumkin: string (""), number (0), boolean (false), obyekt/massiv, yoki null. useStatehook: u faqat komponent ichida va funksiyaning eng tepasida chaqiriladi (shart/tsikl ichida emas — bu "Rules of Hooks", 11.5'da chuqur). Hozircha esda tut: state e'lon qilish har doim komponent boshida, to'g'ridan-to'g'ri.

2.3. State — "snapshot" (har render o'z qiymatiga ega)

text
  ENG MUHIM TUSHUNCHA: har render — state'ning "lahzalik surati" (snapshot)
  Har render'da count — O'SHA render uchun QOTGAN qiymat (o'zgarmas konstanta kabi)

  function Counter() {
    const [count, setCount] = useState(0);
    function handleClick() {
      setCount(count + 1);   // count = 0 (BU render'da)  setCount(1)
      setCount(count + 1);   // count HALI HAM 0 (bir xil render)  setCount(1)
      setCount(count + 1);   // count HALI HAM 0  setCount(1)
      // Natija: 3 emas, 1! (count bu render davomida 0 bo'lib QOTGAN)
    }
    return <button onClick={handleClick}>{count}</button>;
  }

  ┌─────────────────────────────────────────────────────────────┐
  │ Render #1: count = 0  (handleClick ichida count har doim 0)  │
  │  setCount(1) uch marta = "keyingi render'da 1 bo'lsin"      │
  │ Render #2: count = 1  (yangi snapshot)                       │
  └─────────────────────────────────────────────────────────────┘

   count o'zgaruvchisi BIR render ichida HECH QACHON o'zgarmaydi (qotgan surat)
   setCount darrov o'zgartirmaydi — "keyingi render uchun" rejalashtiradi (2.5)

State — snapshot — React'ning eng muhim va eng ko'p chalkashtiriladigan tushunchasi. Har bir render'da state o'zgaruvchisi (count) — o'sha render uchun qotib qolgan qiymat (xuddi const kabi, render davomida o'zgarmaydi). Misolda bitta handler ichida setCount(count + 1) ni uch marta chaqirsak ham natija 3 emas, 1 bo'ladi — chunki count shu render davomida 0 bo'lib qotgan, har uch chaqiruv ham "keyingi render'da 1 bo'lsin" deydi. Ikki hal qiluvchi xulosa: (1) state o'zgaruvchisi bir render ichida hech qachon o'zgarmaydi — u o'sha render'ning "lahzalik surati"; (2) setCount qiymatni darrov o'zgartirmaydi — u keyingi render uchun yangi qiymatni rejalashtiradi (2.5 — asinxron). Agar bitta handler ichida state'ni ketma-ket bir necha marta yangilash kerak bo'lsa — updater funksiya ishlatasiz 2.6-bob. Bu modelni tushunsangiz — "nega state darrov yangilanmayapti?" degan eng keng tuzoqdan butunlay qutulasiz.

2.4. State yangilash re-render keltiradi (UI = f(state) amalda)

text
  JARAYON (state o'zgardi  ekran yangilandi):

  1. setCount(5) chaqirildi
  2. React: "count state'i 5 bo'ladi" deb belgilaydi (rejalashtiradi)
  3. React komponent funksiyasini QAYTA chaqiradi (re-render)
  4. Bu safar useState 5 ni qaytaradi (yangi snapshot — 2.3)
  5. Yangi JSX hosil bo'ladi  Virtual DOM diffing (11.2: 2.1)
  6. Faqat o'zgargan qism haqiqiy DOM'ga yoziladi  ekran yangilandi

  ┌──────────────┐   setCount   ┌──────────────┐   re-render   ┌──────────┐
  │ state o'zgardi│ ───────────► │ React xabardor│ ───────────► │ yangi UI │
  └──────────────┘              └──────────────┘               └──────────┘

   11.1: 2.9 dagi QO'LDA render() YO'QOLDI — React O'ZI qiladi (UI = f(state))
   Siz faqat "ma'lumot qanday" ni boshqarasiz; "qanday ko'rsatish" — React'da

State yangilash re-render — React'ning markaziy mexanizmi va UI = f(state) ning amaliy ko'rinishi. setCount(5) chaqirilganda: React state'ni yangilashni belgilaydi komponent funksiyasini qayta chaqiradi (re-render) bu safar useState yangi qiymatni (5) qaytaradi (2.3 snapshot) yangi JSX hosil bo'ladi Virtual DOM diffing (11.2: 2.1) faqat o'zgargan qism haqiqiy DOM'ga yoziladi ekran yangilanadi. Mana 11.1: 2.9 dagi butun og'riqning yechimi: vanilla'da biz qo'lda render() chaqirar, qaysi DOM bo'lagini yangilashni eslab qolar edik — endi bularning hech biri yo'q. Siz faqat state'ni (ma'lumotni) o'zgartirasiz, "qanday ko'rsatish"ni React o'zi hal qiladi. Bu — deklarativ dasturlashning kuchi: siz nima kerakligini aytasiz, qanday qilishni React biladi. Butun React shu g'oya atrofida quriladi.

2.5. State yangilanishi — asinxron va batched (to'plamli)

text
  setX DARROV o'zgartirmaydi — re-render'ni REJALASHTIRADI (asinxron)
  BATCHING — bir hodisa ichidagi BARCHA setX'lar TO'PLANIB, BITTA re-render qiladi

  function handleClick() {
    setCount(count + 1);     // rejalashtirildi
    setName("Ali");          // rejalashtirildi
    setActive(true);         // rejalashtirildi
    //  React BARCHASINI to'plab, BITTA re-render qiladi (3 ta emas — samarali!)
    console.log(count);      //  HALI ESKI qiymat (re-render hali bo'lgani yo'q)
  }

  ┌────────────────────────────────────────────────────────────┐
  │ 3 ta setX  React kutadi  hammasini birlashtiradi  1 render│
  │ (har setX'da alohida render bo'lganda — 3 marta sekin bo'lardi)│
  └────────────────────────────────────────────────────────────┘

   setX'dan KEYIN darrov state'ni o'qisangiz — ESKI qiymat (yangisi keyingi render'da)
   React 18+ : batching HAMMA joyda (hodisa, promise, setTimeout — avtomatik)

Asinxron va batched yangilanishsetX state'ni darrov o'zgartirmaydi, balki re-render'ni rejalashtiradi (asinxron). Bundan tashqari React batching (to'plamlash) qiladi: bitta hodisa (event handler) ichidagi barcha setX chaqiruvlari to'planib, bitta re-render qilinadi (har biriga alohida render emas — bu samaralilik uchun). Shuning uchun setCount(...) dan keyin darrov console.log(count) qilsangiz — eski qiymatni ko'rasiz (yangisi keyingi render'da paydo bo'ladi — 2.3 snapshot bilan bog'liq). Ikki muhim nuqta: (1) state yangilanishini "darrov" deb o'ylama — u keyingi render'da kuchga kiradi; (2) React 18+ da batching hamma joyda ishlaydi (hodisa, Promise, setTimeout, native event — avtomatik; ilgari faqat React hodisalarida edi). Agar state'ning yangi qiymatiga handler ichida darrov muhtoj bo'lsangiz — o'zgaruvchini alohida hisoblab ishlat (const next = count + 1; setCount(next); foo(next);). Bu mexanizm React ilovasini tez va bashoratli qiladi.

2.6. Updater funksiya — setX(prev => ...) qachon va nega

text
  MUAMMO 2.3-bob: bitta handler'da ketma-ket yangilash count'ni "qotgan" ko'radi

   count'ga tayanish (snapshot — har uchchovi 0 ko'radi):
  setCount(count + 1);   // 0 + 1
  setCount(count + 1);   // 0 + 1 (count hali 0)
  setCount(count + 1);   // 0 + 1  natija: 1 (3 emas!)

   UPDATER FUNKSIYA — React "oldingi" qiymatni beradi (navbatda yangilanadi):
  setCount(prev => prev + 1);   // prev = 0  1
  setCount(prev => prev + 1);   // prev = 1  2  (React navbatda hisoblaydi)
  setCount(prev => prev + 1);   // prev = 2  3   natija: 3 

  QACHON updater (prev =>) ishlatish:
   Yangi qiymat ESKISIGA bog'liq bo'lsa (count + 1, [...prev, x], !prev)
   Bitta handler'da ketma-ket bir necha marta yangilaganda
   Asinxron (setTimeout, promise) ichida yangilaganda (eski snapshot tuzog'idan qochish)

   Qoida: "oldingi qiymatdan kelib chiqsangiz — updater funksiya ishlating"

Updater funksiyasetX(prev => yangi) shakli, bunda React sizga eng so'nggi (navbatdagi) qiymatni prev orqali beradi. 2.3 dagi muammoni hal qiladi: setCount(count + 1) snapshot tufayli countni qotgan ko'radi, lekin setCount(prev => prev + 1) — React har chaqiruvda oldingi natijani uzatadi, shuning uchun ketma-ket uch chaqiruv 0123 ni to'g'ri hisoblaydi. Qachon updater funksiya ishlatish kerak: (1) yangi qiymat eskisiga bog'liq bo'lsa (count + 1, [...prev, item], !prev — toggle); (2) bitta handler'da ketma-ket bir necha marta yangilasangiz; (3) asinxron kod (setTimeout, Promise, debounce) ichida yangilasangiz — u yerda snapshot eskirgan bo'lishi mumkin, prev esa har doim yangi. Oltin qoida: "oldingi qiymatdan kelib chiqsangiz — updater funksiya ishlat" (prev =>). Bevosita yangi qiymat berayotgan bo'lsangiz (setName("Ali") — eskiga bog'liq emas) — oddiy shakl yetadi. Ko'p tajribali dasturchilar har doim updater shaklini afzal ko'radi (xavfsizroq).

2.7. State immutability — mutatsiya qilma, yangi yarat

text
  QOIDA: state'ni HECH QACHON to'g'ridan o'zgartirma (mutate qilma) — YANGI nusxa yarat

   MUTATSIYA (state'ni joyida o'zgartirish — React buni "ko'rmaydi"):
  const [user, setUser] = useState({ name: "Ali", age: 25 });
  user.age = 26;                  //  obyektni joyida o'zgartirdik
  setUser(user);                  //  AYNI obyekt (havola bir xil)  React: "o'zgarmagan"  re-render YO'Q

   YANGI OBYEKT (spread bilan nusxa + o'zgartirish):
  setUser({ ...user, age: 26 }); // yangi obyekt (yangi havola)  React: "o'zgardi"  re-render 

  NEGA: React eski va yangi state'ni HAVOLA (reference) bo'yicha solishtiradi (===)
  - bir xil havola  "o'zgarmagan" deb hisoblaydi (re-render yo'q)
  - yangi havola  "o'zgargan"  re-render

  ┌────────────────────────────────────────────────────────────┐
  │ Primitiv (number, string, boolean): setX(yangi) — muammosiz │
  │ Obyekt/massiv: HAR DOIM yangi nusxa yarat ({...}, [...])    │
  └────────────────────────────────────────────────────────────┘

   Immutability — React performance (===) va bashoratlilik (predictable) asosi

Immutability (o'zgarmaslik) — React'da state'ni hech qachon to'g'ridan-to'g'ri o'zgartirmaslik (mutate qilmaslik), o'rniga yangi nusxa yaratish qoidasi. Nega: React eski va yangi state'ni havola (reference) bo'yicha solishtiradi (=== — yuzaki/shallow taqqoslash). Agar obyektni joyida o'zgartirsangiz (user.age = 26) va aynan o'sha obyektni setUser(user) bilan bersangiz — havola bir xil qoladi, React "o'zgarmagan" deb hisoblaydi va re-render qilmaydi (UI eskirib qoladi). To'g'ri yo'l: yangi obyekt yaratish (setUser({ ...user, age: 26 })) — yangi havola React o'zgarishni ko'radi re-render. Primitiv qiymatlar (number, string, boolean) bilan bu muammo yo'q (setCount(5) — muammosiz), lekin obyekt va massiv bilan har doim yangi nusxa ({...}, [...]) yaratasiz. Immutability tasodifiy qoida emas: u React'ning tez taqqoslashi (===, memo — 11.11), useEffect bog'liqliklari 11.5-bob, Redux 12.2-bob — barchasining asosi. State'ni o'zgarmas deb hisoblash — bashoratli, xatosiz ilovaning kaliti.

2.8. Obyektni state'da yangilash (spread, ichma-ich)

text
  YASSI OBYEKT — spread (...) bilan nusxalab, kerakli maydonni almashtir:
  const [form, setForm] = useState({ name: "", email: "", age: 0 });

  setForm({ ...form, name: "Ali" });           // faqat name o'zgardi, qolgani saqlanadi
  setForm(prev => ({ ...prev, age: 26 }));      // updater bilan (xavfsizroq — 2.6)

  ICHMA-ICH (nested) OBYEKT — har QATLAMNI nusxala (chuqurroq):
  const [user, setUser] = useState({
    name: "Ali",
    address: { city: "Toshkent", street: "Navoiy" }
  });
  //  setUser({ ...user, address: { city: "Samarqand" } })  street YO'QOLADI!
  //  ichki obyektni ham nusxala:
  setUser({
    ...user,
    address: { ...user.address, city: "Samarqand" }   // street saqlanadi
  });

   Chuqur ichma-ich state og'riqli  state'ni YASSI tut yoki Immer/useReducer (11.6)
   Dinamik maydon (forma): setForm({ ...form, [e.target.name]: e.target.value }) — 2.11

Obyektni state'da yangilash — immutability 2.7-bob tufayli yangi obyekt yaratamiz. Yassi (flat) obyekt: spread bilan nusxalab, kerakli maydonni almashtirasiz: setForm({ ...form, name: "Ali" }) (qolgan maydonlar saqlanadi). Updater bilan xavfsizroq: setForm(prev => ({ ...prev, age: 26 })) (e'tibor: obyekt qaytaruvchi strelka funksiyada ({...}) — qavs majburiy). Ichma-ich (nested) obyekt — bu yerda tuzoq bor: agar faqat tashqi qatlamni nusxalasangiz ({ ...user, address: { city: ... } }), ichki obyektning boshqa maydonlari (street) yo'qoladi; shuning uchun har qatlamni nusxalash kerak: { ...user, address: { ...user.address, city: "Samarqand" } }. Chuqur ichma-ich state qo'lda nusxalash og'riqli bo'ladi — ikki yechim: (1) state'ni yassi (flat) tut (chuqur joylashtirmadan saqlan); (2) Immer kutubxonasi (mutatsiya yozuvini immutable qiladi) yoki useReducer 11.6-bob. Dinamik maydon (forma) uchun computed property: { ...form, [e.target.name]: e.target.value } 2.11-bob.

2.9. Massivni state'da yangilash (qo'shish, o'chirish, yangilash)

text
  QOIDA: massivni MUTATSIYA qiluvchi metodlar TAQIQ (push, pop, splice, sort, reverse)
          ular joyida o'zgartiradi (havola bir xil  re-render yo'q — 2.7)
  RUXSAT: yangi massiv qaytaruvchilar ([...], map, filter, slice, concat)

  const [items, setItems] = useState([{id:1, text:"A"}, {id:2, text:"B"}]);

   QO'SHISH (oxiriga / boshiga):
  setItems([...items, { id: 3, text: "C" }]);        // oxiriga (push o'rniga)
  setItems([{ id: 0, text: "Z" }, ...items]);        // boshiga (unshift o'rniga)

   O'CHIRISH (id bo'yicha — filter):
  setItems(items.filter(item => item.id !== 2));     // id=2 dan tashqari hammasi

   YANGILASH (bitta elementni — map):
  setItems(items.map(item =>
    item.id === 1 ? { ...item, text: "Yangi A" } : item   // id=1 ni almashtir, qolgani o'z holida
  ));

   TARTIBLASH (nusxa olib, keyin sort — original'ni buzmaslik):
  setItems([...items].sort((a, b) => a.text.localeCompare(b.text)));  // [...] nusxa MAJBURIY

   push/splice/sort — original'ni buzadi  AVVAL [...] bilan nusxa ol

Massivni state'da yangilash — immutability 2.7-bob tufayli mutatsiya qiluvchi metodlar (push, pop, splice, sort, reverse) taqiqlanadi (ular massivni joyida o'zgartiradi, havola bir xil qoladi re-render bo'lmaydi). O'rniga yangi massiv qaytaruvchi metodlar: qo'shish[...items, yangi] (oxiriga, push o'rniga) yoki [yangi, ...items] (boshiga); o'chirishitems.filter(x => x.id !== id) (shartga mos kelmaydiganlarni qoldiradi); yangilashitems.map(x => x.id === id ? {...x, ...yangilanish} : x) (mos kelganini almashtiradi, qolganini o'z holida qoldiradi); tartiblash[...items].sort(...) (e'tibor: sort original'ni buzadi, shuning uchun avval [...] bilan nusxa ol). Bu naqshlar — React'da massiv state'i bilan ishlashning standarti, ularni yoddan bilishing kerak (ro'yxat, savat, vazifalar — hammasi shu). map/filter ichidagi obyektlarni ham mutatsiya qilma — yangi obyekt qaytar ({...x, ...}).

2.10. Hodisalar (event handlers) — to'g'ri ulash va argument uzatish

text
  HODISA ULASH — funksiyani UZAT (chaqirma!):
   onClick={handleClick}            // funksiya HAVOLASI (React kerak bo'lganda chaqiradi)
   onClick={handleClick()}          // funksiyani CHAQIRDIK  natijasi prop'ga (render'da darrov ishlaydi!)

  ARGUMENT UZATISH — strelka funksiya bilan o'rab:
   onClick={() => handleDelete(id)} // o'ralgan  bosilganda handleDelete(id) chaqiriladi
   onClick={handleDelete(id)}       // darrov chaqiriladi (render paytida — xato)

  KENG TARQALGAN HODISALAR:
  onClick (tugma) | onChange (input/select) | onSubmit (forma) | onInput
  onKeyDown/onKeyUp (klaviatura) | onMouseEnter/Leave | onFocus/onBlur

  EVENT OBYEKT (SyntheticEvent — React o'rovi):
  function handleChange(e) {
    e.target.value         // input qiymati
    e.preventDefault()     // standart harakatni to'xtat (forma — 2.11)
    e.stopPropagation()    // bubbling'ni to'xtat (11.1: 2.6)
  }

   React hodisasi — SyntheticEvent (barcha brauzerda bir xil ishlaydi; ostida native event)

Hodisalar (event handlers) — foydalanuvchi harakatlariga javob. Eng keng xato — funksiyani chaqirib qo'yish: onClick={handleClick()} funksiyani render paytida darrov chaqiradi (natijasi prop'ga tushadi) — to'g'risi onClick={handleClick} (funksiya havolasi, React kerak bo'lganda chaqiradi). Argument uzatish kerak bo'lsa — strelka funksiya bilan o'ra: onClick={() => handleDelete(id)} (bosilganda handleDelete(id) ishlaydi); onClick={handleDelete(id)} esa darrov chaqiriladi (xato). Keng hodisalar: onClick, onChange (input/select), onSubmit (forma), onKeyDown, onMouseEnter, onFocus/onBlur. Handler event obyekt (e) oladi — bu SyntheticEvent (React'ning barcha brauzerda bir xil ishlaydigan o'rovi, ostida native event — 11.1: 2.6): e.target.value (input qiymati), e.preventDefault() (standart harakatni to'xtat — 2.11), e.stopPropagation(). React hodisalari camelCase (onClick, onclick emas — 11.2: 2.5) va event delegation orqali samarali ishlaydi (React barcha hodisalarni root'da tinglaydi).

2.11. Controlled inputs — state bilan boshqariladigan forma

text
  CONTROLLED INPUT — input qiymati STATE'da yashaydi (React — "yagona haqiqat manbai"):

  const [name, setName] = useState("");
  <input
    value={name}                          // qiymat state'dan keladi (React boshqaradi)
    onChange={e => setName(e.target.value)} // har bosishda state yangilanadi
  />

  IKKI TOMONLAMA BOG'LANISH (jonli aylana):
  foydalanuvchi yozadi  onChange  setName  re-render  value yangilanadi  ekran

  ┌─────────────────────────────────────────────────────────┐
  │ value (state  input)  +  onChange (input  state)        │
  │  input HAR DOIM state'ni aks ettiradi (sinxron)          │
  └─────────────────────────────────────────────────────────┘

  TURLI INPUT TURLARI:
  text/textarea:  value={x}            onChange={e => setX(e.target.value)}
  checkbox:       checked={x}          onChange={e => setX(e.target.checked)}
  select:         value={x}            onChange={e => setX(e.target.value)}
  number:         value={x}            onChange={e => setX(Number(e.target.value))}

   value bersangiz, onChange ham BERISH SHART (aks holda "read-only" input — yozib bo'lmaydi)
   Controlled — validatsiya, shartli o'chirish, formatlash oson (11.10 RHF buni soddalashtiradi)

Controlled input — input qiymati state'da yashaydigan forma elementi (React — "yagona haqiqat manbai", single source of truth). Ikki bog'lanish: value={name} (qiymat state'dan inputga) + onChange={e => setName(e.target.value)} (har o'zgarishda input'dan state'ga). Bu ikki tomonlama jonli aylana: foydalanuvchi yozadi onChange setName re-render value yangilanadi ekran. Shuning uchun input har doim state'ni aks ettiradi (sinxron). Turli input turlari biroz farq qiladi: text/textarea/select — value + e.target.value; checkboxchecked + e.target.checked (boolean); number — Number(e.target.value). Ikki muhim qoida: (1) value bersangiz, onChange ham berish shart — aks holda input "read-only" bo'lib qoladi (yozib bo'lmaydi, React ogohlantiradi); (2) controlled input validatsiya, shartli o'chirish, jonli formatlash (telefon, narx)ni osonlashtiradi — chunki qiymat doim sizning qo'lingda. Katta formalar uchun React Hook Form bu naqshni soddalashtiradi 11.10-bob.

2.11a. Controlled vs uncontrolled — ref bilan boshqarilmaydigan input

text
  CONTROLLED 2.11-bob: qiymat STATE'da — React "yagona haqiqat manbai" (odatiy tanlov)
  <input value={name} onChange={e => setName(e.target.value)} />

  UNCONTROLLED: qiymat DOM'ning O'ZIDA yashaydi — React tinglamaydi;
                kerak bo'lganda ref orqali O'QIYMIZ (masalan, submit paytida)
  const inputRef = useRef(null);                    // useRef — 11.5
  <input ref={inputRef} defaultValue="Ali" />       // defaultValue (value EMAS), ref
  // submit'da: inputRef.current.value   hozirgi qiymatni O'QIYMIZ

  FARQ:
  controlled    har bosishda re-render; qiymat doim state'da; validatsiya/formatlash oson
  uncontrolled  re-render yo'q; qiymat DOM'da; faqat kerak bo'lganda o'qiladi

   value + onChange = controlled;  defaultValue + ref = uncontrolled (ikkovini ARALASHTIRMA)
   AMALIYOT: deyarli har doim controlled ishlat (bashoratli, boshqariladigan);
     uncontrolled — faqat oddiy holat, uchinchi tomon DOM kutubxonasi, yoki fayl input (<input type="file">)

Controlled vs uncontrolled — React'da forma inputining ikki yondashuvi. Controlled 2.11-bob — qiymat state'da yashaydi, React uni to'liq boshqaradi (value + onChange); bu odatiy va tavsiya etilgan tanlov. Uncontrolled — qiymat DOM elementining o'zida qoladi, React uni tinglamaydi; siz qiymatga kerak bo'lganda (masalan, submit paytida) ref orqali kirasiz: const inputRef = useRef(null) <input ref={inputRef} defaultValue="Ali" /> inputRef.current.value (useRef 11.5'da chuqur). E'tibor: uncontrolled inputda value emas, defaultValue ishlatiladi (faqat boshlang'ich qiymat, keyin DOM o'zi boshqaradi). Asosiy farq: controlled input har bosishda re-render qiladi (qiymat doim state'da — validatsiya, jonli formatlash, shartli o'chirish oson), uncontrolled esa re-render qilmaydi (qiymat faqat kerak bo'lganda o'qiladi). Ikkovini aralashtirmang (value va defaultValueni birga bermang — 2-bo'lim, Xato 4). Amaliyotda deyarli har doim controlled ishlatiladi (bashoratli, React boshqaruvida); uncontrolled — faqat juda oddiy holatlar, uchinchi tomon DOM kutubxonalari, yoki <input type="file"> (fayl input har doim uncontrolled — brauzer xavfsizligi tufayli).

2.12. Shartli render — barcha usullar va tuzoqlar

text
  1. TERNARY (ikki variant — eng keng):
  {isLoggedIn ? <Profil /> : <Kirish />}

  2. && (faqat bitta holat — "bor yoki yo'q"):
  {error && <p className="error">{error}</p>}      // error bo'lsa ko'rsat, bo'lmasa hech narsa
  {items.length > 0 && <List items={items} />}

  3. ELEMENT O'ZGARUVCHI (murakkab mantiq — return'dan oldin):
  let content;
  if (loading) content = <Spinner />;
  else if (error) content = <Error />;
  else content = <Data data={data} />;
  return <div>{content}</div>;

  4. null QAYTARISH (komponent hech narsa ko'rsatmaslik):
  if (!visible) return null;                        // hech narsa render qilmaydi

   && TUZOG'I — raqam 0:
   {items.length && <List />}   // length=0 bo'lsa  EKRANDA "0" chiqadi! (0 — falsy, lekin render bo'ladi)
   {items.length > 0 && <List />}  // aniq boolean shart
   {!!items.length && <List />}    // yoki boolean'ga majburlash

   if/for JSX {} ICHIDA ishlamaydi (11.2: 2.5)  ternary/&&/element o'zgaruvchi

Shartli render — ma'lumotga qarab turli UI ko'rsatish. To'rt asosiy usul: (1) ternary — ikki variant orasida ({isLoggedIn ? <Profil/> : <Kirish/>}); (2) && — bor-yo'qligi ({error && <p>{error}</p>} — error bo'lsa ko'rsat, bo'lmasa hech narsa); (3) element o'zgaruvchi — murakkab mantiq uchun return'dan oldin if/else bilan o'zgaruvchiga JSX yig'asiz (loading/error/data holatlari uchun ideal — toza JSX); (4) return null — komponent hech narsa render qilmasligi. && tuzog'i (eng keng xato): {items.length && <List/>} — agar length 0 bo'lsa, ekranda "0" chiqib qoladi (0 — falsy, lekin React uni matn sifatida render qiladi); yechim — aniq boolean shart (items.length > 0 && ...) yoki !!. Shuningdek if/for JSX {} ichida ishlamaydi (11.2: 2.5 — ular ifoda emas), shuning uchun har doim ternary/&&/element o'zgaruvchi ishlatasiz. To'g'ri tanlov: ikki variant ternary; bor-yo'q &&; ko'p holat element o'zgaruvchi.

2.13. Ro'yxatlar va key — chuqur (nega kerak, nega index xato)

text
  RO'YXAT — massivni .map() bilan JSX elementlariga aylantirish:
  {users.map(user => <li key={user.id}>{user.name}</li>)}

  KEY NIMA: React'ga har element uchun BARQAROR, UNIKAL "shaxsiy raqam"
   reconciliation (11.2: 2.2) da qaysi element o'zgardi/qo'shildi/o'chdi — aniqlash uchun

  NEGA INDEX (key={i}) XATO — ro'yxat O'ZGARSA (qo'shilsa/o'chsa/tartiblansa):

  Boshida:  [Olma(i=0), Non(i=1), Sut(i=2)]
  Olma o'chdi  [Non(i=0), Sut(i=1)]
   React: "i=0 element matni Olma'dan Non'ga o'zgardi" deb o'ylaydi (NOTO'G'RI!)
   state aralashadi (input qiymati boshqa qatorga "sakraydi"), noto'g'ri render, bug

  TO'G'RI KEY:
   key={user.id}        // barqaror unikal id (DB'dan, yoki yaratishda crypto.randomUUID())
   key={index}          // ro'yxat o'zgarsa — buziladi (faqat STATIK ro'yxatda mayli)
   key={Math.random()}  //  har render'da YANGI  React hammasini qayta yaratadi (sekin + state yo'qoladi)

   key — JSX prop kabi yozilADI, lekin React ICHIDA ishlatadi (props sifatida kelmaydi)
   key faqat .map() (yoki aka-uka ro'yxat)da kerak; bitta elementga kerak emas

Ro'yxatlar va key — React'ning eng ko'p xato qilinadigan joylaridan biri. Massivni .map() bilan JSX elementlariga aylantirasiz, va har elementga key berasiz. key nima: React'ga har element uchun barqaror, unikal "shaxsiy raqam" — u reconciliation (11.2: 2.2) da qaysi element o'zgargani/qo'shilgani/o'chirilganini aniqlash uchun ishlatiladi. Nega index (key={i}) xato: agar ro'yxat o'zgarsa (element qo'shilsa, o'chsa, tartiblansa), indekslar siljiydi va React "i=0 ning matni o'zgardi" deb noto'g'ri xulosa chiqaradi — natijada komponent state'i aralashadi (input qiymati boshqa qatorga "sakraydi"), noto'g'ri render, qiyin topiladigan buglar. To'g'ri key: barqaror unikal id (key={user.id} — DB'dan kelgan id, yoki element yaratilganda crypto.randomUUID() bilan generatsiya qilingan). Xatolar: key={index} (faqat statik, o'zgarmaydigan ro'yxatda mayli), key={Math.random()} ( — har render'da yangi key React hamma elementni qayta yaratadi sekin + state yo'qoladi). key JSX prop kabi yoziladi, lekin React uni ichida ishlatadi (komponentga prop sifatida kelmaydi — agar id kerak bo'lsa, alohida prop ber). key faqat ro'yxatlarda kerak.

2.14. Lifting state up — state'ni ulashish va qayerda saqlash

text
  MUAMMO: ikki aka-uka komponent BIR XIL ma'lumotni ulashishi kerak
          (masalan: qidiruv input va natijalar ro'yxati)

  YECHIM: state'ni ENG YAQIN UMUMIY OTAga "ko'tarish" (lift up)
           ota state'ni saqlaydi, bolalarga props (qiymat) + callback (o'zgartirish) beradi

         App  (state: query)             state shu yerda (umumiy ota)
        /    \
  SearchBar   ResultList
  query={query}      results=filtered(query)    props (qiymat pastga)
  onChange={setQuery}                             callback (xabar yuqoriga — 11.2: 2.10)

  QAYERDA STATE SAQLASH (qoidalar):
  - Faqat BITTA komponent ishlatsa  o'sha komponentda (colocation — yaqin tut)
  - BIR NECHA komponent ulashsa  eng yaqin UMUMIY otada (lift up)
  - BUTUN ilova ulashsa  Context 12.1-bob yoki global store (Redux — 12.2)

   "Single source of truth" — har ma'lumot uchun BITTA egasi (nusxalama)
   State'ni keraksiz yuqoriga ko'tarma (faqat ulashish kerak bo'lganda — aks holda yaqin tut)

Lifting state up (state'ni ko'tarish) — ikki yoki undan ortiq komponent bir xil ma'lumotni ulashishi kerak bo'lganda, state'ni ularning eng yaqin umumiy otasiga ko'taradigan naqsh. Ota state'ni saqlaydi va bolalarga qiymatni props orqali, o'zgartirish funksiyasini callback orqali beradi ("data down, events up" — 11.2: 2.10). Masalan, qidiruv input (SearchBar) va natijalar (ResultList) bir query state'ini ulashadi query ularning otasi App'da saqlanadi. Qayerda state saqlash (muhim qaror): (1) faqat bitta komponent ishlatsa — o'sha komponentda (colocation — state'ni ishlatadigan joyga yaqin tut); (2) bir necha komponent ulashsa — eng yaqin umumiy otada (lift up); (3) butun ilova ulashsa — Context 12.1-bob yoki global store (Redux/Zustand — 12.2, 12.5). Ikki tamoyil: (1) "single source of truth" — har ma'lumotning bitta egasi bo'lsin (nusxalama, aks holda sinxronlash muammosi qaytadi — 11.1: 2.9); (2) state'ni keraksiz yuqoriga ko'tarma — faqat ulashish zarur bo'lganda (aks holda yaqin tut — ortiqcha re-render va murakkablikdan qoch — 11.11).

2.15. State strukturasini to'g'ri tuzish (tekis, guruhli, dublikatsiz)

text
  YAXSHI STATE STRUKTURASI — kelajakdagi buglarning yarmini oldini oladi

  1. HISOBLASH MUMKIN BO'LGANNI STATE'DA SAQLAMA (derived state — 2.14):
   const [items] + const [count]  // count = items.length'dan kelib chiqadi (dublikat!)
   const [items] ...  const count = items.length;   // render paytida hisobla

  2. DUBLIKAT/QARAMA-QARSHI STATE'DAN QOCH (bir haqiqat — ikki joyda emas):
   const [items] + const [selectedItem]  // selectedItem — items'dagi obyekt NUSXASI
      item o'zgarsa, ikkovi rassinxron bo'ladi (qaysi biri to'g'ri?)
   const [items] + const [selectedId]    // faqat ID saqla  obyektni items'dan top

  3. BOG'LIQ STATE'LARNI GURUHLA (birga o'zgarsa — bitta obyekt):
  ~ const [x, setX] + const [y, setY]      // kursor pozitsiyasi — doim birga
   const [pos, setPos] = useState({ x: 0, y: 0 });   // guruhlangan (birga yangilanadi)

  4. CHUQUR ICHMA-ICH EMAS, YASSI (flat) TUT 2.8-bob:
   chuqur nested obyekt (yangilash og'riqli)
   yassi struktura yoki id bo'yicha "normallashtirilgan" ({ [id]: item })

   Qoida: MINIMAL, TEKIS, DUBLIKATSIZ state  qolganini HISOBLA

State strukturasi — state'ni qanday tashkil qilish kelgusidagi buglarning katta qismini belgilaydi. To'rt tamoyil: (1) hisoblash mumkin bo'lganni state'da saqlamangcount = items.length kabi qiymat state emas, uni render paytida hisoblang (derived state — 2.14, Xato 8; aks holda ikki joyni qo'lda sinxronlash muammosi qaytadi); (2) dublikat va qarama-qarshi state'dan qoching — masalan tanlangan elementning butun nusxasini saqlamang, faqat IDsini saqlang (selectedId) va obyektni ro'yxatdan toping — aks holda element o'zgarganda ikki nusxa rassinxron bo'lib qoladi ("bitta haqiqat" buziladi); (3) birga o'zgaradigan bog'liq state'larni guruhlang — masalan kursor x/y doim birga yangilansa, ularni bitta obyekt ({ x, y }) qiling; (4) chuqur ichma-ich emas, yassi (flat) tuting 2.8-bob — chuqur joylashtirilgan state'ni immutable yangilash og'riqli, shuning uchun yassi yoki id bo'yicha "normallashtirilgan" ({ [id]: item }) struktura afzal. Umumiy qoida: state minimal, tekis va dublikatsiz bo'lsin — qolgan hamma narsani undan hisoblang. Bu tamoyillar 11.6 (useReducer) va 12-QISM (global state)'da yanada muhimroq bo'ladi.


3. Sintaksis — tez ma'lumotnoma

text
E'LON 2.2-bob:      const [x, setX] = useState(boshlang'ich)
YANGILASH 2.4-bob:  setX(yangiQiymat)   |   setX(prev => prev + 1)  // updater 2.6-bob
LAZY INIT:        useState(() => qimmatHisob())   // funksiya — faqat 1-render'da
OBYEKT 2.8-bob:     setForm({ ...form, name: "Ali" })   |  {...form, [e.target.name]: e.target.value}
MASSIV  2.9-bob:  setItems([...items, yangi])   |  [yangi, ...items]
MASSIV :        setItems(items.filter(i => i.id !== id))
MASSIV :        setItems(items.map(i => i.id === id ? {...i, ...upd} : i))
HODISA 2.10-bob:    onClick={fn}  |  onClick={() => fn(arg)}  |  onChange={e => setX(e.target.value)}
INPUT 2.11-bob:     <input value={x} onChange={e => setX(e.target.value)} />  // controlled
CHECKBOX:         <input type="checkbox" checked={x} onChange={e => setX(e.target.checked)} />
UNCONTROLLED:     <input ref={inputRef} defaultValue="..." />  // qiymat: inputRef.current.value (2.11a)
SHART 2.12-bob:     {cond ? <A/> : <B/>}  |  {cond && <A/>}  |  if(!x) return null
RO'YXAT 2.13-bob:   {arr.map(x => <li key={x.id}>{x.name}</li>)}   // unikal key

4. Batafsil kod namunalari

Misol 1 — Eng oddiy state: hisoblagich (2.1, 2.2, 2.4)

jsx
import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);          // state e'lon (boshlang'ich 0)

  return (
    <div>
      <p>Hisob: {count}</p>                        {/* state'ni ko'rsatamiz */}
      <button onClick={() => setCount(count + 1)}>+1</button>  {/* state'ni oshiramiz */}
      <button onClick={() => setCount(count - 1)}>-1</button>
      <button onClick={() => setCount(0)}>Reset</button>
    </div>
  );
}
//  setCount  re-render  yangi count  ekran yangilanadi (UI = f(state)). render() YO'Q!

Misol 2 — Lazy initial state (qimmat boshlang'ich hisob)

jsx
function App() {
  //  Har render'da ishlaydi (lekin natija faqat 1-marta kerak — isrof):
  // const [data] = useState(qimmatHisob());

  //  FUNKSIYA bersang — React uni FAQAT birinchi render'da chaqiradi (lazy):
  const [data, setData] = useState(() => {
    const saved = localStorage.getItem("data");   // qimmat: localStorage o'qish
    return saved ? JSON.parse(saved) : [];         // faqat 1-render'da bajariladi
  });

  return <div>{data.length} ta element</div>;
}
//  useState(qiymat) — qiymat har render'da hisoblanadi; useState(() => qiymat) — faqat 1-marta

Misol 3 — Snapshot tuzog'i: nega 3 emas, 1? (2.3)

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

  function handleTriple() {
    setCount(count + 1);     // count = 0  setCount(1)
    setCount(count + 1);     // count HALI 0 (snapshot)  setCount(1)
    setCount(count + 1);     // count HALI 0  setCount(1)
    //  Natija: 1 (3 emas!) — count bu render davomida 0 bo'lib QOTGAN (2.3)
  }

  return <button onClick={handleTriple}>{count} — uchta +1</button>;
}
//  Bu — "nega yangilanmayapti" tuzog'ining ildizi. Yechim — Misol 4 (updater)

Misol 4 — Updater funksiya: to'g'ri ketma-ket yangilash (2.6)

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

  function handleTriple() {
    setCount(prev => prev + 1);   // prev = 0  1
    setCount(prev => prev + 1);   // prev = 1  2  (React navbatda beradi)
    setCount(prev => prev + 1);   // prev = 2  3   Natija: 3 
  }

  // Asinxron holatda ham updater shart (snapshot eskiradi):
  function handleDelayed() {
    setTimeout(() => setCount(prev => prev + 1), 1000);  // 1s keyin — prev har doim yangi
  }

  return (
    <>
      <button onClick={handleTriple}>{count} — +3</button>
      <button onClick={handleDelayed}>Kechikkan +1</button>
    </>
  );
}

Misol 5 — Obyekt state: forma (spread — 2.8)

jsx
function ProfileForm() {
  const [form, setForm] = useState({ name: "", email: "", age: 0 });

  // Bitta universal handler — barcha maydonlar uchun (dinamik maydon nomi — 2.11)
  function handleChange(e) {
    const { name, value } = e.target;
    setForm(prev => ({ ...prev, [name]: value }));  // [name] — computed property (qaysi maydon?)
  }

  return (
    <form>
      <input name="name" value={form.name} onChange={handleChange} placeholder="Ism" />
      <input name="email" value={form.email} onChange={handleChange} placeholder="Email" />
      <input name="age" type="number" value={form.age} onChange={handleChange} />
      <pre>{JSON.stringify(form, null, 2)}</pre>      {/* state'ni jonli ko'rsatamiz */}
    </form>
  );
}
//  Bitta handleChange — barcha inputlarni boshqaradi (name atributi orqali ajratiladi)

Misol 6 — Ichma-ich obyekt state (nested — 2.8)

jsx
function Settings() {
  const [user, setUser] = useState({
    name: "Ali",
    address: { city: "Toshkent", street: "Navoiy" },   // ichma-ich obyekt
  });

  function updateCity(city) {
    setUser(prev => ({
      ...prev,                                   // tashqi qatlam nusxasi
      address: { ...prev.address, city },        // ichki qatlam HAM nusxalanadi (street saqlanadi)
    }));
  }
  //  { ...prev, address: { city } } bo'lsa — street YO'QOLADI! (2.8)

  return (
    <div>
      <p>{user.name} — {user.address.city}, {user.address.street}</p>
      <button onClick={() => updateCity("Samarqand")}>Shaharni o'zgartir</button>
    </div>
  );
}

Misol 7 — Massiv state: qo'shish va o'chirish (2.9)

jsx
function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: "React o'rganish" },
    { id: 2, text: "Loyiha qilish" },
  ]);
  const [input, setInput] = useState("");

  function addTodo() {
    if (!input.trim()) return;                     // bo'sh bo'lmasin
    const newTodo = { id: crypto.randomUUID(), text: input };  // unikal id (2.13)
    setTodos([...todos, newTodo]);                 //  oxiriga (push o'rniga — 2.9)
    setInput("");                                  // inputni tozala
  }

  function removeTodo(id) {
    setTodos(todos.filter(t => t.id !== id));       //  id bo'yicha o'chir (filter — 2.9)
  }

  return (
    <div>
      <input value={input} onChange={e => setInput(e.target.value)} />
      <button onClick={addTodo}>Qo'shish</button>
      <ul>
        {todos.map(todo => (                        // ro'yxat (2.13)
          <li key={todo.id}>                        {/* unikal key (id) */}
            {todo.text}
            <button onClick={() => removeTodo(todo.id)}></button>  {/* argument uzatish — 2.10 */}
          </li>
        ))}
      </ul>
    </div>
  );
}

Misol 8 — Massiv state: elementni yangilash (toggle — 2.9)

jsx
function TaskList() {
  const [tasks, setTasks] = useState([
    { id: 1, text: "Sport", done: false },
    { id: 2, text: "O'qish", done: true },
  ]);

  function toggleDone(id) {
    setTasks(tasks.map(task =>                      // map — bitta elementni almashtirish
      task.id === id
        ? { ...task, done: !task.done }             // mosini: done'ni teskari qil (yangi obyekt)
        : task                                       // qolganini o'z holida (o'zgartirmaymiz)
    ));
  }

  return (
    <ul>
      {tasks.map(task => (
        <li key={task.id} style={{ textDecoration: task.done ? "line-through" : "none" }}>
          <input type="checkbox" checked={task.done} onChange={() => toggleDone(task.id)} />
          {task.text}
        </li>
      ))}
    </ul>
  );
}
//  map ichida mos kelmaganlarni O'ZGARTIRMASDAN qaytaramiz (faqat keraklisini yangilaymiz)

Misol 9 — Controlled inputs: barcha turlar (2.11)

jsx
function RegistrationForm() {
  const [name, setName] = useState("");                  // text
  const [agree, setAgree] = useState(false);             // checkbox
  const [role, setRole] = useState("user");              // select
  const [age, setAge] = useState(18);                    // number

  return (
    <form>
      {/* text */}
      <input value={name} onChange={e => setName(e.target.value)} placeholder="Ism" />

      {/* checkbox — checked + e.target.checked (boolean) */}
      <label>
        <input type="checkbox" checked={agree} onChange={e => setAgree(e.target.checked)} />
        Shartlarga roziman
      </label>

      {/* select — value + e.target.value */}
      <select value={role} onChange={e => setRole(e.target.value)}>
        <option value="user">Foydalanuvchi</option>
        <option value="admin">Admin</option>
      </select>

      {/* number — Number() bilan o'girish */}
      <input type="number" value={age} onChange={e => setAge(Number(e.target.value))} />

      {/* tugma faqat rozi bo'lsa faol (shartli o'chirish — controlled kuchi) */}
      <button disabled={!agree}>Ro'yxatdan o'tish</button>
    </form>
  );
}

Misol 10 — Forma submit va preventDefault (2.10, 2.11)

jsx
function LoginForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");

  function handleSubmit(e) {
    e.preventDefault();                              //  sahifa qayta yuklanishini to'xtat (11.1: 2.6)
    if (!email.includes("@")) {
      setError("Email noto'g'ri");                   // shartli xato (2.12 da ko'rsatamiz)
      return;
    }
    setError("");
    console.log("Kirish:", { email, password });     // bu yerda API chaqiruvi (12.4)
  }

  return (
    <form onSubmit={handleSubmit}>                    {/* onSubmit — formaga, tugmaga emas */}
      <input value={email} onChange={e => setEmail(e.target.value)} placeholder="Email" />
      <input type="password" value={password} onChange={e => setPassword(e.target.value)} />
      {error && <p className="error">{error}</p>}     {/* shartli render (&&) — 2.12 */}
      <button type="submit">Kirish</button>
    </form>
  );
}

Misol 11 — Shartli render: barcha usullar (2.12)

jsx
function DataView({ loading, error, data }) {
  // 1. Element o'zgaruvchi (ko'p holat — eng toza)
  let content;
  if (loading) content = <Spinner />;
  else if (error) content = <p className="error">Xato: {error}</p>;
  else if (data.length === 0) content = <p>Ma'lumot yo'q</p>;
  else content = <ul>{data.map(d => <li key={d.id}>{d.name}</li>)}</ul>;

  return (
    <div>
      {content}                                       {/* 1. o'zgaruvchi */}

      {/* 2. ternary (ikki variant) */}
      {loading ? <small>Yuklanmoqda...</small> : <small>Tayyor</small>}

      {/* 3. && (bor-yo'q) — TO'G'RI boolean shart (length > 0, raqam 0 tuzog'i — 2.12) */}
      {data.length > 0 && <p>Jami: {data.length} ta</p>}

      {/*  {data.length && ...} bo'lsa — 0 da ekranda "0" chiqardi 2.12-bob */}
    </div>
  );
}

Misol 12 — Lifting state up: aka-uka ulashishi (2.14)

jsx
// Bola 1 — qidiruv input (state'ni o'zi saqlamaydi, otadan oladi)
function SearchBar({ query, onQueryChange }) {
  return (
    <input value={query} onChange={e => onQueryChange(e.target.value)} placeholder="Qidirish..." />
  );
}

// Bola 2 — natijalar (otadan filtrlangan ma'lumot oladi)
function ResultList({ results }) {
  return <ul>{results.map(r => <li key={r.id}>{r.name}</li>)}</ul>;
}

// Ota — state SHU YERDA (umumiy ota), ikki bolaga ulashadi
function SearchPage({ products }) {
  const [query, setQuery] = useState("");            // state ko'tarildi (lifted up)
  const filtered = products.filter(p =>              // query bo'yicha filtr (render paytida hisob)
    p.name.toLowerCase().includes(query.toLowerCase())
  );

  return (
    <div>
      <SearchBar query={query} onQueryChange={setQuery} />  {/* qiymat + callback pastga */}
      <ResultList results={filtered} />                      {/* hisoblangan natija pastga */}
    </div>
  );
}
//  query — BITTA egasi (SearchPage); ikki bola uni ulashadi (single source of truth — 2.14)

Misol 13 — Toggle va boolean state (modal, accordion)

jsx
function Accordion({ title, children }) {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div className="accordion">
      <button onClick={() => setIsOpen(prev => !prev)}>   {/* toggle — updater 2.6-bob */}
        {title} {isOpen ? "▲" : "▼"}                        {/* ternary belgi 2.12-bob */}
      </button>
      {isOpen && <div className="content">{children}</div>} {/* && — ochiq bo'lsa ko'rsat 2.12-bob */}
    </div>
  );
}
//  setIsOpen(prev => !prev) — eskiga bog'liq  updater 2.6-bob; ikki marta bossang to'g'ri ishlaydi

Misol 14 — Ro'yxat filtri va saralash (state + hisoblangan qiymat)

jsx
function ProductBoard({ products }) {
  const [search, setSearch] = useState("");
  const [sortBy, setSortBy] = useState("name");      // "name" yoki "price"

  // Hisoblangan qiymat — state'da SAQLAMAYMIZ (render paytida hosil — single source)
  const visible = products
    .filter(p => p.name.toLowerCase().includes(search.toLowerCase()))   // filtr
    .sort((a, b) =>                                   // saralash (yangi massivda — filter nusxa bergan)
      sortBy === "price" ? a.price - b.price : a.name.localeCompare(b.name)
    );

  return (
    <div>
      <input value={search} onChange={e => setSearch(e.target.value)} placeholder="Qidirish" />
      <select value={sortBy} onChange={e => setSortBy(e.target.value)}>
        <option value="name">Nom bo'yicha</option>
        <option value="price">Narx bo'yicha</option>
      </select>
      {visible.length > 0 ? (                          // shartli render (ternary — 2.12)
        <ul>{visible.map(p => <li key={p.id}>{p.name} — {p.price}</li>)}</ul>
      ) : (
        <p>Hech narsa topilmadi</p>
      )}
    </div>
  );
}
//  "visible" — state EMAS (search/sortBy'dan KELIB CHIQADI). Hosilani state'da saqlama 11.5-bob!

Misol 15 — Hammasini birlashtirgan mini-ilova: "Vazifalar"

jsx
function TaskApp() {
  const [tasks, setTasks] = useState([]);            // ro'yxat (massiv state)
  const [input, setInput] = useState("");            // input (controlled)
  const [filter, setFilter] = useState("all");       // filtr: all/active/done

  function addTask() {
    if (!input.trim()) return;
    setTasks(prev => [...prev, { id: crypto.randomUUID(), text: input, done: false }]);  //  updater
    setInput("");
  }
  const toggle = id => setTasks(prev => prev.map(t => t.id === id ? { ...t, done: !t.done } : t)); // 
  const remove = id => setTasks(prev => prev.filter(t => t.id !== id));                            // 

  // Hisoblangan: filtrlangan ro'yxat (state EMAS — tasks/filter'dan)
  const visible = tasks.filter(t =>
    filter === "all" ? true : filter === "done" ? t.done : !t.done
  );

  return (
    <div>
      <input value={input} onChange={e => setInput(e.target.value)}
             onKeyDown={e => e.key === "Enter" && addTask()} />   {/* Enter bilan ham — 2.10 */}
      <button onClick={addTask}>Qo'shish</button>

      <div>
        {["all", "active", "done"].map(f => (         // filtr tugmalari (ro'yxat — key)
          <button key={f} onClick={() => setFilter(f)}
                  style={{ fontWeight: filter === f ? "bold" : "normal" }}>{f}</button>
        ))}
      </div>

      {visible.length === 0 && <p>Vazifa yo'q</p>}     {/* shartli (&&) — 2.12 */}
      <ul>
        {visible.map(task => (                          // ro'yxat (key — 2.13)
          <li key={task.id}>
            <input type="checkbox" checked={task.done} onChange={() => toggle(task.id)} />
            <span style={{ textDecoration: task.done ? "line-through" : "none" }}>{task.text}</span>
            <button onClick={() => remove(task.id)}></button>
          </li>
        ))}
      </ul>
      <p>Jami: {tasks.length} | Bajarilgan: {tasks.filter(t => t.done).length}</p>
    </div>
  );
}
//  11.1: 2.9 dagi QO'LDA render() butunlay YO'Q — faqat state'ni o'zgartiramiz, React qoladi (UI=f(state))

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

1) Oddiy o'zgaruvchi vs state

text
 let count = 0; count++  (re-render yo'q, render'da tiklanadi — 2.1)
 const [count, setCount] = useState(0); setCount(count + 1)

2) Ketma-ket yangilash

text
 setCount(count+1); setCount(count+1)  (snapshot — natija +1 — 2.3)
 setCount(p => p+1); setCount(p => p+1)  (updater — natija +2 — 2.6)

3) Obyekt/massivni yangilash

text
 user.age = 26; setUser(user)  /  items.push(x); setItems(items)  (mutatsiya — re-render yo'q — 2.7)
 setUser({...user, age:26})  /  setItems([...items, x])  (yangi nusxa)

4) Hodisa ulash

text
 onClick={handleClick()}  (darrov chaqiriladi — render'da — 2.10)
 onClick={handleClick}  yoki  onClick={() => handleClick(id)}

5) Controlled input

text
 <input value={name} />  (onChange yo'q — read-only, yozib bo'lmaydi — 2.11)
 <input value={name} onChange={e => setName(e.target.value)} />

6) && tuzog'i (raqam 0)

text
 {items.length && <List/>}  (0 da ekranda "0" — 2.12)
 {items.length > 0 && <List/>}  (aniq boolean)

7) Ro'yxat key

text
 key={index}  yoki  key={Math.random()}  (ro'yxat o'zgarsa buziladi — 2.13)
 key={item.id}  (barqaror unikal id)

8) Hosilangan qiymatni state'da saqlash

text
 const [filtered, setFiltered] = useState([]); ... (search o'zgarsa qo'lda sinxronlash — 11.1: 2.9 qaytadi)
 const filtered = items.filter(...)  (render paytida hisobla — Misol 14)

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — "State o'zgaryapti, lekin ekran yangilanmayapti"

Sababi: obyekt/massivni mutatsiya qildingiz (havola bir xil React ko'rmaydi — 2.7). Yechimi: yangi nusxa yarat ({...obj}, [...arr], map/filter — 2.8, 2.9).

Xato 2 — "setX'dan keyin darrov o'qidim, eski qiymat chiqdi"

Sababi: state yangilanishi asinxron (keyingi render'da kuchga kiradi — 2.5). Yechimi: yangi qiymatni alohida o'zgaruvchiga ol (const next = ...; setX(next); use(next)), yoki effektni useEffect bilan kuzat 11.5-bob.

Xato 3 — Too many re-renders. React limits the number of renders

Sababi: render paytida setX chaqirdingiz (onClick={setX(1)} — chaqiruv, yoki to'g'ridan return'da). Bu cheksiz tsikl: render setX render setX... Yechimi: onClick={() => setX(1)} (funksiya bilan o'ra — 2.10).

Xato 4 — A component is changing an uncontrolled input to be controlled

Sababi: valueni undefined bilan boshladingiz, keyin qiymat berdingiz. Yechimi: boshlang'ich qiymat ber (useState(""), useState(0) — 2.2, 2.11).

Xato 5 — Ro'yxatda input qiymati noto'g'ri qatorga "sakraydi"

Sababi: key={index} ishlatdingiz, ro'yxat o'zgardi 2.13-bob. Yechimi: barqaror unikal key={item.id}.

Xato 6 — Cannot update a component while rendering a different component

Sababi: bir komponent render paytida boshqasining state'ini o'zgartirmoqda. Yechimi: state o'zgarishini hodisa ichida yoki useEffectda bajar 11.5-bob, render paytida emas.

Xato 7 — Ekranda kutilmagan "0" yoki "false" chiqadi

Sababi: && chap tomonida raqam (0) yoki noto'g'ri qiymat 2.12-bob. Yechimi: aniq boolean shart (length > 0, Boolean(x), !!x).


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • DOM og'rig'i (11.1: 2.9): state + re-render qo'lda render()ni butunlay yo'qotadi.
  • Komponent/props 11.2-bob: props o'zgarmas; o'zgaruvchi ma'lumot — state; callback 2.10-bob bilan bola otaga.
  • Hooks 11.5-bob: useState — birinchi hook; useEffect — state o'zgarishiga reaksiya.
  • useReducer 11.6-bob: murakkab state mantiqi (ko'p bog'liq state).
  • Forma 11.10-bob: controlled inputs — React Hook Form buni soddalashtiradi; useRef esa uncontrolled input asosi (2.11a, 11.5).
  • Performance 11.11-bob: keraksiz re-render; memo/useMemo immutability'ga tayanadi 2.7-bob.
  • State boshqaruvi (12-QISM): Context/Redux — lifting state up 2.14-bob kengaytmasi.
  • Data fetching 12.4-bob: server ma'lumoti ham state (loading/error/data — 2.12).

8. Eng yaxshi amaliyotlar (best practices)

  • Hosilangan qiymatni state'da saqlama (filtr, hisob — render paytida hisobla — Misol 14, Xato 8).
  • Immutability (obyekt/massivni hech qachon mutatsiya qilma — yangi nusxa — 2.7, 2.8, 2.9).
  • Updater funksiya (oldingi qiymatga bog'liq bo'lsa prev => — 2.6).
  • State'ni yaqin tut (faqat kerakli komponentda; ulashish kerak bo'lganda lift up — 2.14).
  • Single source of truth (har ma'lumotning bitta egasi — nusxalama — 2.14).
  • Controlled inputs (value + onChange — forma ustidan to'liq nazorat — 2.11).
  • Barqaror unikal key (id — index/random emas — 2.13).
  • && da aniq boolean (raqam 0 tuzog'idan qoch — 2.12).
  • Handler'ni o'ra (() => fn(arg) — render'da chaqirma — 2.10).
  • State'ni minimal tut (faqat kerakli ma'lumot; qolganini hisobla — kam state, kam bug).
  • State strukturasi (tekis, guruhli, dublikatsiz — obyekt nusxasi emas, ID saqla — 2.15).
  • Controlled'ni afzal ko'r (uncontrolled/ref — faqat oddiy holat yoki fayl input — 2.11a).

9. Amaliy loyiha: "Interaktiv Xaridlar Ro'yxati (Shopping List)"

11.1-bobda xuddi shu g'oyani vanilla DOM bilan amalga oshirdik (og'riq bilan). Endi uni React state bilan qayta yozamiz — va farqni yaqqol his qilamiz.

Maqsad

To'liq interaktiv xaridlar ro'yxati: mahsulot qo'shish, sonini o'zgartirish, "olindi" belgilash, o'chirish, filtrlash, umumiy hisob — barchasi state bilan.

Talablar (requirements)

  1. Qo'shish: input (controlled — 2.11) + tugma; bo'sh qo'shilmasin; Enter bilan ham ishlasin (Misol 15).
  2. Massiv state: har element {id, name, qty, bought} — unikal id (crypto.randomUUID() — 2.13).
  3. Son boshqaruvi: +/ tugmalari (map bilan yangilash — 2.9, Misol 8); son 1 dan kam bo'lmasin.
  4. "Olindi" toggle: checkbox bilan boughtni almashtir (updater — 2.6, Misol 13).
  5. O'chirish: filter bilan (2.9, Misol 7).
  6. Filtr: "Hammasi / Olinmagan / Olingan" — hisoblangan ro'yxat (state EMAS — Misol 14).
  7. Shartli render: ro'yxat bo'sh bo'lsa "Ro'yxat bo'sh", filtr natijasi 0 bo'lsa boshqa xabar 2.12-bob.
  8. Statistika: "Jami N ta, olingan M ta" — hisoblangan (render paytida — 2.14).
  9. Immutability: hech qayerda mutatsiya yo'q (push/splice/joyida o'zgartirish — taqiq — 2.7).
  10. Tahrirlash (bonus): mavjud mahsulot nomini ikki marta bosib tahrirlash (inline edit — qo'shimcha state).

Maslahatlar (hint)

  • State'ni minimal tut: items, input, filter — yetadi. Filtrlangan ro'yxat va statistika — hisoblangan (state emas — 2.14, Xato 8).
  • Massivni o'zgartirganda har doim map/filter/[...] (push/splice yo'q — 2.9).
  • Oldingi qiymatga bog'liq har yangilashda updater (prev => — 2.6).
  • keyitem.id (index emas — 2.13).
  • 11.1-bobdagi vanilla versiyangiz bilan solishtiring: render() ni necha marta yozgan edingiz? Bu yerda nol marta (React o'zi qiladi). Mana farq.

"Tayyor" mezonlari (acceptance criteria)

  • Qo'shish/o'chirish ishlaydi (controlled input, filter).
  • Son +/ (map bilan, immutable).
  • "Olindi" toggle (checkbox, updater).
  • Filtr (hammasi/olingan/olinmagan) — hisoblangan ro'yxat.
  • Shartli render (bo'sh holatlar).
  • Statistika hisoblangan (state'da saqlanmaydi).
  • Hech qanday mutatsiya yo'q (faqat yangi nusxalar).
  • Barcha key — unikal id.
  • UI hech qachon ma'lumotga zid kelmaydi (avtomatik sinxron).

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


10. Xulosa va keyingi bobga ko'prik

Bu bobda React'ning yuragi — state — ni chuqur o'rgandik:

  • State (komponent xotirasi, nega oddiy o'zgaruvchi yetmaydi — 2.1); useState anatomiyasi 2.2-bob; state — snapshot (har render o'z qiymati — 2.3); yangilash re-render (UI = f(state) — 2.4).
  • Asinxron/batched yangilanish 2.5-bob; updater funksiya (prev => — 2.6); immutability (yangi nusxa — 2.7); obyekt 2.8-bob va massiv 2.9-bob ni to'g'ri yangilash.
  • Hodisalar (handler, argument, synthetic — 2.10); controlled inputs 2.11-bob va uncontrolled/ref farqi (2.11a); shartli render (ternary/&&/o'zgaruvchi + tuzoqlar — 2.12); ro'yxat va key 2.13-bob; lifting state up 2.14-bob; state strukturasi (tekis, dublikatsiz — 2.15).

Endi siz interaktiv UI qura olasiz — tugma, forma, ro'yxat, filtr — va eng muhimi, 11.1-bobdagi butun og'riq (qo'lda render(), sinxronlash) butunlay yo'qoldi. UI = f(state) endi siz uchun jonli haqiqat.

Keyingi bob — 11.5-bob: Hooks — useState, useEffect, useContext, useRef. State'ni o'rgandik; endi hooklar dunyosiga to'liq kiramiz. Rules of Hooks (nega yuqorida, nega shartsiz), useEffect (komponentni tashqi dunyo bilan bog'lash — API chaqiruvi, taymer, obuna — va cleanup), useContext (props drilling'siz ma'lumot ulashish), useRef (DOM elementga to'g'ridan kirish va render'siz qiymat saqlash). Bu hooklar — har real React ilovasining nafasi.


Foydalanilgan rasmiy/ishonchli manbalar

  • React rasmiy hujjati (react.dev) — "State: A Component's Memory", "Render and Commit", "State as a Snapshot", "Queueing a Series of State Updates", "Updating Objects in State", "Updating Arrays in State"
  • react.dev — "Responding to Events", "Conditional Rendering", "Rendering Lists", "Sharing State Between Components", "Choosing the State Structure", "Preserving and Resetting State"
  • react.dev — useState va useRef API reference; "Keeping Components Pure"; "React and the DOM: Controlled vs Uncontrolled Components"
  • MDN Web Docs — Array metodlari (map, filter, sort), spread sintaksisi (...), computed property nomlari, crypto.randomUUID()

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
11.4-bob: State, hodisalar, shartli render, ro'yxatlar va keys — Wisar