IlmHamroh
Dasturlash kitobi (eski nashr)/11-QISM — React1/17-dars39 daqiqa
Mundarija (44)

DOM API va CRUD — brauzerda HTML/CSS/JS takrori (11.1-bob)

11-QISM — Frontend: React · 1-mavzu


1. Kirish va motivatsiya

5–10 QISM'larda biz backend dunyosini chuqur o'rgandik: Node.js, API, ma'lumotlar bazasi, NestJS, arxitektura, DevOps. Backend — bu sahnaning orqasi (oshxona): ma'lumotni saqlaydi, hisoblaydi, qaytaradi. Endi 11-QISM'da sahnaning old tomoniga — foydalanuvchi ko'radigan va teginadigan qismga — frontendga o'tamiz. Bu — sizning kasbingdagi eng ko'zga ko'rinadigan, eng ko'p ish beriladigan va eng tez o'zgaradigan soha. Va uning markazida — React turadi.

Lekin React'ni o'rganishdan oldin bitta poydevorni tosh qotgan darajada mustahkam qilib olishimiz kerak: DOM (Document Object Model). Sababi oddiy va muhim — React aslida nima qiladi? U DOM bilan ishlashni avtomatlashtiradi. React'ni "sehrli" deb qabul qilsangiz, hech qachon chuqur tushunmaysiz; uni "men qo'lda qiladigan DOM ishlarini men o'rnimga, lekin aqlli qilib bajaradigan vosita" deb tushunsangiz — har bir hook, har bir key, har bir re-render sizga mantiqiy ko'rinadi. Shuning uchun bu bobda biz DOM'ni qo'lda (vanilla JS bilan) boshqaramiz — element yaratamiz, o'zgartiramiz, o'chiramiz (CRUD) — va eng muhimi, buning og'rig'ini his qilamiz. Aynan shu og'riq — React'ning butun mavjudligi sababi.

Bu bob 2.16-bob (DOM manipulyatsiya) va 0.5-bob (brauzer qanday ishlaydi)ning chuqurlashtirilgan, frontend rakursidan takrori: brauzer sahifani qanday quradi (critical rendering path — DOM, CSSOM, render tree, layout, paint), DOM daraxti va Node turlari, tanlash (querySelector oilasi), CRUD (createElement → append → update → remove), atribut/class/style/dataset, hodisalar (delegation, bubbling), reflow/repaint (nega qo'lda DOM sekin), DocumentFragment (batching), BOM (window/location/history), Web Storage (localStorage), Fetch API va to'liq CRUD sikli (server bilan GET/POST/PUT/DELETE — bobning "API (CRUD)" qismi), va eng muhimi — imperativ DOM'ning fundamental muammosi (UI ↔ state'ni qo'lda sinxron ushlab turishning iloji yo'qligi), bu bizni to'g'ri declarative yondashuvga — React'ga — olib keladi.

O'xshatish: DOM — bu jonli qo'g'irchoq teatri sahnasi. HTML — sahnaning boshlang'ich dekoratsiyasi (qo'g'irchoqlar qayerda turibdi). CSS — ularning kiyimi va yorug'lik. JavaScript esa — qo'g'irchoqchining iplari: har bir qo'g'irchoqning qo'lini, og'zini, joyini qo'lda tortib boshqarasiz. Kichik spektaklda (3 ta qo'g'irchoq) bu qiziq. Lekin 200 ta qo'g'irchoq bo'lsa-chi? Har biri ma'lumotga qarab o'zgarsa-chi (foydalanuvchi yozgan matn, server javobi)? Siz 200 ta ipni bir vaqtda, qo'lda, xatosiz tortib turolmaysiz — bittasini unutsangiz, sahna "yolg'on" ko'rsatadi (ma'lumot bir xil, ekran boshqacha). React — bu avtomat qo'g'irchoqchi: siz unga faqat "men sahna mana shunday ko'rinishini xohlayman" deb tasvirlaysiz, u esa qaysi ipni qachon tortishni o'zi hisoblab, eng kam harakat bilan bajaradi. Bu bobda biz iplarni qo'lda tortib ko'ramiz — keyingi bobda esa avtomatga o'tamiz.

Nega muhim?

  • React'ning poydevori — React = aqlli DOM boshqaruvi; DOM'ni bilmasdan React "sehr" bo'lib qoladi.
  • Og'riqni his qilish — imperativ DOM bilan kichik ilova yozsangiz, React'ning nega borligini hech qachon unutmaysiz.
  • Debugging — brauzer, render, reflow tushunchasi performance va xatolarni tuzatishda hal qiluvchi 11.11-bob.
  • Vanilla baza — ba'zan React kerak emas (oddiy sahifa, widget); DOM API'ni bilish — universal ko'nikma.

2. Nazariya — chuqur tushuntirish

2.1. Brauzer sahifani qanday quradi (Critical Rendering Path)

text
  SIZ YUBORGAN: <html>...</html> + CSS + JS (matn — 0.4, 0.5)

  BRAUZER BOSQICHMA-BOSQICH (Critical Rendering Path):

  1. HTML  ──parse──►  DOM daraxti      (Document Object Model — obyektlar daraxti)
  2. CSS   ──parse──►  CSSOM daraxti     (CSS Object Model — stillar daraxti)
  3. DOM + CSSOM ──►  RENDER TREE        (ko'rinadigan elementlar + stillari)
                                          (display:none — bu yerda YO'Q)
  4. RENDER TREE ──►  LAYOUT (reflow)     (har element QAYERDA, qancha KATTA — geometriya)
  5. LAYOUT ──────►  PAINT                (piksellar — rang, matn, chegara chiziladi)
  6. PAINT ───────►  COMPOSITE            (qatlamlar birlashtiriladi → ekran)

  ┌──────┐   ┌───────┐   ┌────────────┐   ┌────────┐   ┌───────┐   ┌───────────┐
  │ HTML │──►│  DOM  │──►│            │──►│ LAYOUT │──►│ PAINT │──►│ COMPOSITE │
  └──────┘   └───────┘   │ RENDER TREE│   └────────┘   └───────┘   └───────────┘
  ┌──────┐   ┌───────┐   │            │
  │ CSS  │──►│ CSSOM │──►│            │
  └──────┘   └───────┘   └────────────┘

  ❗ JS DOM'ni o'zgartirsa → brauzer 4-6 bosqichni QAYTA bajaradi (reflow/repaint)

Critical Rendering Path — brauzer matn (HTML/CSS) ni ekrandagi piksellarga aylantiradigan bosqichlar zanjiri. (1) HTML → DOM (obyektlar daraxti — 0.5); (2) CSS → CSSOM (stillar daraxti); (3) ikkalasi birlashib → render tree (faqat ko'rinadigan elementlar — display:none bu yerda yo'q); (4) layout/reflow (har element ekranda qayerda va qancha katta — geometriya hisoblanadi); (5) paint (piksellar — rang, matn, chegara chiziladi); (6) composite (qatlamlar birlashtiriladi → ekran). Eng muhim xulosa: JavaScript DOM'ni o'zgartirganda, brauzer layout/paint bosqichlarini qayta bajaradi (reflow/repaint — 2.7). Demak DOM bilan qanchalik ko'p va tartibsiz ishlasak, brauzer shunchalik ko'p qayta hisoblaydi — bu performance'ning asosiy manbai. React aynan shu qayta-hisoblashlarni minimallashtirish uchun yaratilgan.

2.2. DOM nima — daraxt va Node turlari

text
  HTML matn:                          DOM daraxti (obyektlar):

  <html>                              document
    <body>                              └─ html (Element)
      <h1>Salom</h1>                        └─ body (Element)
      <ul>                                      ├─ h1 (Element)
        <li>Bir</li>                            │   └─ "Salom" (Text node)
        <li>Ikki</li>                           └─ ul (Element)
      </ul>                                         ├─ li → "Bir" (Text)
    </body>                                         └─ li → "Ikki" (Text)
  </html>

  NODE TURLARI:
  - Element node   — teg (<div>, <li>) — eng ko'p ishlatiladigan
  - Text node      — teg ichidagi MATN ("Salom") — alohida node!
  - Attribute      — atribut (class="...", id="...")
  - Comment, Document, DocumentFragment 2.8-bob

  ❗ document — kirish nuqtasi (butun daraxt ildizi, global obyekt)
  ❗ "Salom" matni — h1 ning ichidagi ALOHIDA text node (element emas)

DOM (Document Object Model) — HTML hujjatning xotiradagi jonli obyektlar daraxti sifatidagi ko'rinishi. Brauzer HTML matnini o'qib, har bir tegni obyekt (node) ga aylantiradi va ularni ota-bola munosabatlari bilan daraxt qilib bog'laydi. Node turlari: Element (teg — <div>, <li> — eng ko'p ishlatamiz), Text (teg ichidagi matn — diqqat: matn alohida node, elementning bir qismi emas), Attribute (atribut), Comment, Document. document — butun daraxtning ildizi va kirish nuqtasi (global obyekt — har doim shundan boshlaymiz). DOM "jonli" (live): JavaScript bu obyektlarni o'zgartirsa, brauzer ekranni yangilaydi. DOM — HTML faylning o'zi emas, balki uning brauzer xotirasidagi dasturlash interfeysi (API): JS shu API orqali sahifani o'qiydi va o'zgartiradi.

2.3. DOM'ni o'qish va element tanlash (Read — querySelector oilasi)

text
  ZAMONAVIY (tavsiya — CSS selektor sintaksisi bilan):
  document.querySelector(".card")        → MOS kelgan BIRINCHI element (yoki null)
  document.querySelectorAll("li")        → BARCHA mos elementlar (NodeList)
  element.querySelector(...)             → faqat shu element ICHIDA qidiradi

  ESKI / TEZ (bitta narsa uchun):
  document.getElementById("app")         → id bo'yicha (eng tez, # belgisiz)
  document.getElementsByClassName("x")   → jonli HTMLCollection (kam ishlatiladi)
  document.getElementsByTagName("li")    → jonli HTMLCollection

  NAVIGATSIYA (qarindoshlarga o'tish):
  el.parentElement      el.children       el.firstElementChild
  el.nextElementSibling el.closest(".x")  el.matches(".x")

  ❗ querySelector — null qaytarishi mumkin (element topilmasa) → tekshirish
  ❗ querySelectorAll → NodeList (massiv EMAS, lekin forEach bor; map yo'q)

Element tanlash — DOM bilan har qanday ishning birinchi qadami (avval elementni "ushlab olamiz", keyin o'zgartiramiz). Zamonaviy va eng moslashuvchan usul — querySelector(selector) (CSS selektor sintaksisi bilan birinchi mos elementni qaytaradi — .class, #id, div > p) va querySelectorAll(selector) (barcha mos elementlar — NodeList). Eski lekin tez usullar: getElementById (id bo'yicha — # belgisiz, eng tez), getElementsByClassName/TagName (jonli HTMLCollection). Navigatsiya: parentElement, children, nextElementSibling, closest(selector) (yuqoriga eng yaqin mosini topadi). Ikki tuzoq: (1) querySelector element topmasa null qaytaradi — to'g'ridan-to'g'ri .textContent qilsangiz Cannot read properties of null xatosi (2.6 xatolar); (2) querySelectorAll natijasi NodeList — massiv emas, forEach bor lekin map/filter yo'q (kerak bo'lsa [...nodeList] yoki Array.from bilan massivga aylantiriladi — 2.7).

2.4. DOM CRUD — yaratish, o'zgartirish, o'chirish

text
  CREATE (yaratish va daraxtga qo'shish):
  const li = document.createElement("li");   // 1. element yarat (hali sahnada YO'Q)
  li.textContent = "Yangi vazifa";            // 2. ichini to'ldir
  ul.append(li);                              // 3. daraxtga ulash (endi ko'rinadi)
  ul.prepend(li)      // boshiga
  el.before(node) / el.after(node)            // yon tomoniga

  READ (o'qish):
  el.textContent       // ichidagi MATN (xavfsiz — teg sifatida o'qimaydi)
  el.innerHTML         // ichidagi HTML (qulay, lekin XSS XAVFI — 2.5)
  el.value             // input/textarea qiymati (forma — 11.10)

  UPDATE (o'zgartirish):
  el.textContent = "..."     el.classList.add("active")     el.style.color = "red"
  el.setAttribute("href","#")  el.dataset.id = "5"

  DELETE (o'chirish):
  el.remove();                                // o'zini o'chiradi (zamonaviy)
  parent.removeChild(el);                     // eski usul

DOM CRUD — element yaratish (Create), o'qish (Read), o'zgartirish (Update), o'chirish (Delete) — ya'ni sahifani dinamik boshqarishning to'rt amali. Create uch qadamli: createElement (element yaratiladi, lekin hali daraxtda yo'q — ko'rinmaydi) → ichini to'ldirish → append (yoki prepend/before/after) bilan daraxtga ulash (endi ekranda paydo bo'ladi). Read: textContent (faqat matn — xavfsiz), innerHTML (HTML sifatida — qulay, lekin XSS xavfi — foydalanuvchi kiritgan matnni hech qachon innerHTML ga qo'ymang — 14-QISM). Update: textContent, classList.add/remove/toggle, style, setAttribute, dataset. Delete: el.remove() (zamonaviy — element o'zini o'chiradi). Diqqat qiling: bu yerda biz har bir o'zgarishni qo'lda, qadam-baqadam aytyapmiz — "shu elementni yarat, shu yerga qo'sh, shu matnni o'zgartir". Bu imperativ uslub 2.10-bob. React'da esa biz faqat natijani tasvirlaymiz, qadamlarni emas.

2.5. Atribut, class, style va dataset

text
  CLASS (eng ko'p — CSS bilan ishlash):
  el.classList.add("active")        el.classList.remove("active")
  el.classList.toggle("open")       el.classList.contains("active")  // true/false

  STYLE (to'g'ridan-to'g'ri — kam tavsiya, class afzal):
  el.style.color = "red";           el.style.display = "none";
  // camelCase: backgroundColor (background-color EMAS)

  ATRIBUT:
  el.setAttribute("href", "/home")  el.getAttribute("href")  el.removeAttribute("disabled")
  el.id, el.href, el.src            // ko'p atributlar to'g'ridan property sifatida ham

  DATASET (data-* — o'z ma'lumotingizni elementga "yopishtirish"):
  <li data-id="42" data-done="false">
  el.dataset.id        // "42"   (data-id)
  el.dataset.done      // "false"

  ❗ class afzal style'dan (CSS'da turadi — ajratilgan, qayta ishlatiladi)
  ❗ dataset — DOM va JS ma'lumotini bog'lashning "qo'lbola" usuli (React'da kerak emas)

Atribut/class/style/dataset — elementning ko'rinishi va ma'lumotini boshqarish vositalari. classList — eng ko'p ishlatiladigan: add, remove, toggle (bor bo'lsa o'chir, yo'q bo'lsa qo'sh — switch tugmalar uchun ideal), contains. style — to'g'ridan-to'g'ri inline stil (lekin class afzalroq — stil CSS'da, ajratilgan turadi; xususiyatlar camelCase: backgroundColor, background-color emas). Atribut: setAttribute/getAttribute/removeAttribute. dataset (data-*) — o'zingizning maxsus ma'lumotingizni HTML elementiga "yopishtirish" usuli (masalan data-id="42" → el.dataset.id). dataset — vanilla JS'da DOM elementi bilan JS ma'lumotini bog'lashning qo'lbola yechimi (qaysi tugma qaysi vazifaga tegishli?). Bu — imperativ DOM'ning yana bir og'rig'i: ma'lumot (JS obyekt) va ko'rinish (DOM element) alohida yashaydi, ularni sun'iy bog'lab turishga to'g'ri keladi. React'da ma'lumot va UI bitta joyda (komponent) yashaydi — bu muammo yo'qoladi.

2.6. Hodisalar (Events) — addEventListener, bubbling, delegation

text
  HODISA TINGLASH:
  button.addEventListener("click", (event) => {
    event.target          // hodisa SODIR BO'LGAN element
    event.preventDefault()  // brauzer standart xatti-harakatini to'xtat (forma submit, link)
    event.stopPropagation() // bubbling'ni to'xtat
  });

  BUBBLING (ko'piklanish) — hodisa boladan OTAga ko'tariladi:
  <ul> ← bu yerda ham "eshitiladi" (3)
    <li> ← (2)
      <button> ← bosildi (1) → yuqoriga ko'tariladi: button → li → ul → body
  </ul>

  EVENT DELEGATION (delegatsiya) — 1 ta listener bilan KO'P bolani boshqarish:
  ul.addEventListener("click", (e) => {
    if (e.target.matches(".delete-btn")) { /* o'chir */ }   // qaysi bola bosildi?
  });
  // 100 ta tugmaga 100 ta listener O'RNIGA — 1 ta otaga (xotira/performance)

Hodisalar — foydalanuvchi harakatlariga (click, input, submit, keydown...) javob berish mexanizmi. addEventListener(turi, ishlovchi) — elementga hodisa tinglovchi biriktiradi; ishlovchi funksiya event obyektini oladi: event.target (hodisa sodir bo'lgan aniq element), event.preventDefault() (brauzer standart harakatini to'xtatadi — masalan forma yuborilib sahifa qayta yuklanishini — 11.10), event.stopPropagation(). Bubbling (ko'piklanish): hodisa boladan otaga ko'tariladi (button → li → ul → body) — shuning uchun otada tinglab, qaysi bola bosilganini event.target orqali bilish mumkin. Bu — event delegation (delegatsiya): 100 ta tugmaga 100 ta listener o'rniga 1 ta otaga listener qo'yib, e.target.matches(...) bilan ajratish (xotira va performance afzalligi — 2.16). React'da hodisalar boshqacha (synthetic events, onClick prop) — lekin asosida aynan shu bubbling/delegation mexanizmi yotadi (React barcha hodisalarni root'da delegatsiya qiladi). Demak bu tushuncha React'da ham hal qiluvchi.

2.7. Reflow va repaint — nega qo'lda DOM sekin

text
  REPAINT (qayta bo'yash) — faqat KO'RINISH o'zgaradi (rang, ko'rinmaslik):
  el.style.color = "red"   → layout o'zgarmaydi, faqat qayta bo'yaladi (arzonroq)

  REFLOW (layout qayta hisoblash) — GEOMETRIYA o'zgaradi (o'lcham, joy):
  el.style.width = "200px"  → brauzer BUTUN sahifa joylashuvini qayta hisoblaydi (QIMMAT!)
  el.remove()  el.append(...)  el.offsetHeight (o'qish ham!)

  ❌ YOMON — tsiklda 1000 marta reflow (har iteratsiyada DOM'ga teginish):
  for (let i = 0; i < 1000; i++) {
    ul.innerHTML += `<li>${i}</li>`;   // har safar: butun ul qayta quriladi + reflow
  }

  ✅ YAXSHI — bir marta DOM'ga teginish (2.8 fragment yoki bir string):
  let html = "";
  for (let i = 0; i < 1000; i++) html += `<li>${i}</li>`;
  ul.innerHTML = html;                 // 1 marta reflow

  ❗ Layout thrashing — o'qish/yozishni aralashtirish (read→write→read) ketma-ket reflow

Reflow va repaint — DOM o'zgarganda brauzer bajaradigan ikki xil qayta-hisoblash. Repaint (qayta bo'yash) — faqat ko'rinish o'zgarsa (rang, visibility) — nisbatan arzon. Reflow (layout qayta hisoblash) — geometriya o'zgarsa (o'lcham, joylashuv, element qo'shish/o'chirish) — brauzer butun (yoki katta) sahifa joylashuvini qaytadan hisoblaydi — qimmat. Asosiy sahna: agar tsiklda 1000 marta DOM'ga tegsangiz (innerHTML += yoki har iteratsiyada append), 1000 marta reflow bo'ladi — sahifa qotadi. Yechim — o'zgarishlarni to'plab, DOM'ga bir marta tegish (string to'plab innerHTML, yoki DocumentFragment — 2.8). Yana bir tuzoq — layout thrashing: o'qish (offsetHeight) va yozishni ketma-ket aralashtirish brauzerni har safar reflow'ga majbur qiladi. Mana React'ning eng katta texnik sababi: React o'zgarishlarni Virtual DOM'da to'playdi, eng kam farqni hisoblaydi (diffing), va haqiqiy DOM'ga bir marta, eng optimal qilib qo'llaydi (12.2-bobda batafsil). Siz qo'lda qiladigan bu optimizatsiyalarni React avtomatik qiladi.

2.8. DocumentFragment va o'zgarishlarni to'plash (batching)

text
  DOCUMENTFRAGMENT — "vaqtinchalik, ko'rinmas konteyner" (xotirada, sahnada YO'Q):

  const fragment = document.createDocumentFragment();   // bo'sh, ko'rinmas idish
  for (let i = 0; i < 100; i++) {
    const li = document.createElement("li");
    li.textContent = `Element ${i}`;
    fragment.append(li);             // fragmentga qo'shamiz — REFLOW YO'Q (sahnada emas)
  }
  ul.append(fragment);               // 1 MARTA DOM'ga ulanadi → 1 marta reflow

  ┌─────────────────────────────────────────────────────────┐
  │ 100 ta append to'g'ridan ul'ga  →  ~100 reflow (sekin)   │
  │ 100 ta append fragment'ga + 1   →  1 reflow (tez) ✅     │
  └─────────────────────────────────────────────────────────┘

  ❗ fragment ul'ga qo'shilgach — BO'SHAYDI (bolalari ul'ga ko'chadi)

DocumentFragment — DOM'ning "vaqtinchalik, ko'rinmas idishi": u xotirada yashaydi, lekin asosiy daraxtga ulanmagan, shuning uchun unga element qo'shganda reflow bo'lmaydi 2.7-bob. Strategiya: barcha yangi elementlarni avval fragmentga to'playmiz (reflow'siz), so'ng fragmentni bir marta haqiqiy DOM'ga ulaymiz → faqat bitta reflow. 100 ta elementni to'g'ridan-to'g'ri qo'shsak ~100 reflow; fragment orqali — 1 ta. Bu — vanilla JS'da performance'ning klassik usuli. Va bu — aynan React'ning ishlash printsipining qo'lbola modeli: React ham o'zgarishlarni "vaqtinchalik" joyda (Virtual DOM) to'playdi va haqiqiy DOM'ga eng kam, eng optimal yangilanish bilan qo'llaydi. Fragment'ni tushunsangiz — Virtual DOM'ning nega kerakligini allaqachon his qilgan bo'lasiz.

2.9. Imperativ DOM'ning fundamental muammosi (nega React kerak)

text
  MUAMMO: ma'lumot (state) va ko'rinish (DOM) — IKKI ALOHIDA joyda yashaydi
          → ularni QO'LDA sinxron ushlab turish kerak (har o'zgarishda!)

  Misol: savatda 3 mahsulot. Foydalanuvchi bittasini o'chirdi.
  SIZ QO'LDA quyidagilarning HAMMASINI yangilashingiz kerak:
  ✏️ massivdan o'chir          (ma'lumot)
  ✏️ <li> ni DOM'dan o'chir    (ro'yxat)
  ✏️ "Jami: 3 ta" → "2 ta"     (hisoblagich)
  ✏️ umumiy narxni qayta hisobla va yangila   (summa)
  ✏️ savat bo'shasa "Bo'sh" xabarini ko'rsat  (shart)

  → BITTASINI unutsangiz → UI YOLG'ON ko'rsatadi (ma'lumot 2 ta, ekran 3 ta)
  → Ilova o'sgani sayin bu sinxronlash EKSPONENSIAL murakkablashadi
  → Bu — frontend'dagi xatolarning eng katta MANBAI

  ❗ Muammo "DOM'ni qanday o'zgartirish" emas — "QAYSI joylarni o'zgartirishni
     ESLAB qolish va HECH BIRINI o'tkazib yubormaslik"

Imperativ DOM'ning tub muammosi — bu "DOM'ni o'zgartirish qiyin" emas (uni o'rgandik, oson). Asl muammo: ma'lumot (JS dagi massiv/obyekt — state) va uning ko'rinishi (DOM elementlari) ikki alohida dunyoda yashaydi, va har bir o'zgarishda siz ularni qo'lda, bir-biriga moslab yangilashing kerak. Savatdan bitta mahsulot o'chirilganda: massivdan o'chirasiz, <li>ni o'chirasiz, "Jami" hisoblagichini yangilaysiz, narxni qayta hisoblaysiz, savat bo'shasa "Bo'sh" xabarini chiqarasiz — beshta joy, va bittasini unutsangiz UI yolg'on ko'rsatadi (ma'lumot bilan ekran bir-biriga mos kelmaydi). Ilova o'sgani sayin bu "sinxronlash" eksponensial murakkablashadi va frontend xatolarining eng katta manbai bo'ladi. Muammoning mohiyati — "qaysi joylarni yangilashni eslab qolish". Mana shu yerda React keladi: "Ma'lumotni o'zgartir, UI'ni MENGA qo'y".

2.10. Declarative vs imperative — React falsafasiga ko'prik

text
  IMPERATIV (vanilla — "QANDAY qilish" — qadam-baqadam buyruq):
  const li = document.createElement("li");
  li.textContent = task.title;
  li.classList.add("task");
  ul.append(li);
  counter.textContent = tasks.length;
  // ... har o'zgarishda qaysi DOM'ni qanday yangilashni QO'LDA aytasiz

  DEKLARATIV (React — "NIMA bo'lishini" — natijani tasvirlash):
  function TaskList({ tasks }) {
    return (
      <>
        <ul>{tasks.map(t => <li className="task">{t.title}</li>)}</ul>
        <p>Jami: {tasks.length}</p>
      </>
    );
  }
  // "UI ma'lumotga qarab MANA SHUNDAY ko'rinadi" — qadamlarni React hisoblaydi

  ┌──────────────┬─────────────────────────┬──────────────────────────┐
  │              │ IMPERATIV (vanilla)     │ DEKLARATIV (React)       │
  ├──────────────┼─────────────────────────┼──────────────────────────┤
  │ Siz aytasiz  │ HAR QADAMNI             │ FAQAT NATIJANI           │
  │ Sinxronlash  │ qo'lda (xato manbai)    │ avtomatik (React)        │
  │ Fikrlash     │ "DOM'ni qanday o'zgartira│ "UI ma'lumotning funksiyasi│
  │              │  man?"                  │  UI = f(state)"          │
  └──────────────┴─────────────────────────┴──────────────────────────┘

Imperativ va deklarativ — frontend'dagi ikki tafakkur uslubi. Imperativ (vanilla DOM — bu bobda o'rgandik): kompyuterga qanday qilishni qadam-baqadam buyurasiz ("element yarat, matnni qo'y, ro'yxatga qo'sh, hisoblagichni yangila..."). Deklarativ (React): natija qanday ko'rinishini tasvirlaysiz, qadamlarni hisoblashni vositaga qoldirasiz ("UI ma'lumotga qarab mana shunday ko'rinadi"). Eng muhim formula: UI = f(state) — foydalanuvchi interfeysi ma'lumotning funksiyasi. Siz faqat ma'lumotni (state) o'zgartirasiz; React esa yangi UI'ni hisoblab, haqiqiy DOM'ni eng optimal tarzda yangilaydi (2.7, 2.8 dagi optimizatsiyalarni avtomatik qiladi). Bu — restoranga o'xshaydi: imperativ = oshpazga har bir harakatni aytib turish ("pichoqni ol, sabzini kes, tovaga sol..."); deklarativ = "menga osh kerak" deyish (qanday tayyorlashni oshpaz biladi). React'ni o'rganish — aslida bu yangi tafakkurga o'tish. Keyingi boblar shu g'oyani ochib beradi.

2.11. DOM manipulyatsiyaning qolgan quroli: insertAdjacentHTML, cloneNode, replaceChild

text
  insertAdjacentHTML(pozitsiya, html)  — HTML'ni ANIQ joyga qo'shish (innerHTML += dan tez):
    "beforebegin"  → elementning O'ZIDAN oldin
    "afterbegin"   → element ICHIga, boshiga
    "beforeend"    → element ICHIga, oxiriga (eng ko'p — append'ga o'xshash)
    "afterend"     → elementning O'ZIDAN keyin
    ul.insertAdjacentHTML("beforeend", `<li>${xavfsizMatn}</li>`);
    ❗ innerHTML += butun konteynerni QAYTA quradi (eski listenerlar o'ladi);
       insertAdjacent... mavjudini saqlab, faqat yangisini qo'shadi.

  cloneNode(deep)  — elementning NUSXASI:
    const copy = tpl.cloneNode(true);   // true = bolalari bilan chuqur nusxa
    const copy = tpl.cloneNode(false);  // false = faqat o'zi (bolasiz)
    // <template> teg bilan birga — DOM shablonlarini takrorlashning tez usuli

  replaceChild / replaceWith  — bir elementni boshqasiga ALMASHTIRISH:
    old.replaceWith(yangi);             // zamonaviy (old o'rniga yangi turadi)
    parent.replaceChild(yangi, old);    // eski API (tartibga e'tibor: yangi, keyin eski)

  ❗ innerHTML — foydalanuvchi ma'lumoti bilan XAVFLI (XSS — 2.4). Ishonchli/statik
     HTML uchungina; aks holda createElement + textContent yoki matnni ekranlash.

Qolgan manipulyatsiya vositalari — CRUD'ning 2.4-bob kundalik bo'lmagan, ammo muhim to'ldiruvchilari. insertAdjacentHTML(pozitsiya, html) — HTML matnini elementga aniq to'rt pozitsiyadan biriga (beforebegin, afterbegin, beforeend, afterend) joylaydi; innerHTML += dan afzalligi shundaki, u konteynerni qaytadan qurmaydi (innerHTML += esa butun ichki HTML'ni o'chirib qayta o'rnatadi — mavjud hodisa tinglovchilari yo'qoladi va reflow ortadi). cloneNode(deep) — element nusxasini oladi (true — bolalari bilan chuqur nusxa, false — faqat o'zi); <template> tegi bilan birga DOM shablonlarini tez takrorlashda ishlatiladi. replaceWith (zamonaviy) va replaceChild (eski) — mavjud elementni boshqasi bilan almashtiradi. insertAdjacentHTML ham innerHTML kabi HTML'ni bajaradi, shuning uchun foydalanuvchi kiritgan matn bilan XSS xavfi bir xil — faqat ishonchli/statik HTML uchun.

2.12. BOM — Browser Object Model (window, location, history, navigator, screen)

text
  window — brauzer oynasi = GLOBAL obyekt (barcha global o'zgaruvchi/funksiya shunda):
    window.innerWidth / innerHeight    // ko'rinadigan oyna o'lchami (px)
    window.setTimeout / setInterval    // vaqt bo'yicha kod (aslida window.metodi)
    window.alert / confirm / prompt    // brauzer dialoglari

  location — joriy URL (o'qish VA o'zgartirish):
    location.href        // to'liq URL ("https://sayt.uz/mahsulot?id=5#izoh")
    location.pathname    // "/mahsulot"     location.search  // "?id=5"
    location.hash        // "#izoh"
    location.href = "/login"    // BOSHQA sahifaga o'tish (to'liq qayta yuklash)
    location.reload()           // sahifani qayta yuklash

  history — brauzer tarixi (orqaga/oldinga; SPA routing asosi):
    history.back()  history.forward()
    history.pushState(state, "", "/yangi-url")   // URL'ni sahifani qayta yuklamay o'zgartirish
    // ❗ React Router aynan shu pushState ustiga qurilgan (11-QISM keyingi boblar)

  navigator — brauzer/qurilma haqida:  navigator.language ("uz")  navigator.onLine (true/false)
  screen    — ekran:  screen.width / height (butun monitor)

BOM (Browser Object Model) — DOM sahifaning ichini (hujjat) boshqarsa, BOM brauzer oynasi va muhitini boshqaradigan obyektlar to'plamidir. Markazida window turadi — u brauzerdagi global obyekt: har bir global o'zgaruvchi, funksiya, hatto document ham aslida windowning xususiyati (window.document), setTimeout ham window.setTimeout. location — joriy URL bilan ishlash (href, pathname, search, hash; location.href = "..." bilan boshqa sahifaga o'tish). history — brauzer navigatsiya tarixi; ayniqsa history.pushState muhim: u URL'ni sahifani qayta yuklamay o'zgartiradi — bu SPA (Single Page Application) va React Routerning butun asosidir (11-QISM keyingi boblar shuni ochadi). navigator (til, onlayn holati) va screen (monitor o'lchami) — muhit haqida ma'lumot. BOM standartlashtirilmagan (brauzerlar biroz farq qiladi), lekin location/historyni bilish — routing va autentifikatsiya (redirect) uchun shart.

2.13. localStorage, sessionStorage va sahifa hayot sikli (DOMContentLoaded vs load)

text
  WEB STORAGE — ma'lumotni BRAUZERDA (klientda) saqlash (server emas):
    localStorage      — DOIMIY (brauzer yopilsa ham qoladi; qo'lda o'chirilguncha)
    sessionStorage    — VAQTINCHA (faqat shu tab ochiq turganda; tab yopilsa — o'chadi)

    localStorage.setItem("kalit", "qiymat");      // yozish
    const v = localStorage.getItem("kalit");      // o'qish (yo'q bo'lsa null)
    localStorage.removeItem("kalit");             // bittasini o'chirish
    localStorage.clear();                         // hammasini

    ❗ FAQAT string saqlaydi → obyekt uchun JSON:
    localStorage.setItem("savat", JSON.stringify(savatObyekt));   // yozish
    const savat = JSON.parse(localStorage.getItem("savat")) ?? [];// o'qish (null himoyasi)
    ❗ ~5MB limit; SINXRON (katta ma'lumot UI'ni bloklaydi); parol/token — ehtiyot bo'ling

  SAHIFA HAYOT SIKLI (kod QACHON ishlashi):
    DOMContentLoaded  — HTML tahlil qilinib, DOM TAYYOR (rasm/CSS kutilmaydi) — TEZroq
    load              — HAMMA resurs (rasm, stil, shrift) yuklandi — kechroq
    document.addEventListener("DOMContentLoaded", () => { /* DOM bilan xavfsiz ishlash */ });
    ❗ <script defer> yoki </body> oxirida bo'lsa — DOM allaqachon tayyor (odatda kifoya)

Web Storage — ma'lumotni foydalanuvchi brauzerida (serverga bormay) saqlash mexanizmi. localStorage — doimiy (brauzer yopilib qayta ochilsa ham qoladi), sessionStorage — vaqtinchalik (faqat joriy tab ochiq turganda). Ikkalasi ham setItem/getItem/removeItem/clear bilan ishlaydi. Muhim cheklov: faqat matn (string) saqlaydi — obyekt yoki massivni saqlash uchun JSON.stringify bilan yozib, JSON.parse bilan o'qish kerak. Yana: ~5MB limit, sinxron (katta ma'lumot bosh (main) thread'ni bloklaydi), va maxfiy ma'lumot (token, parol) uchun xavfsiz emas (XSS orqali o'g'irlanadi — 14-QISM). Sahifa hayot sikli: DOMContentLoaded hodisasi HTML tahlil qilinib DOM tayyor bo'lganda (rasm/stil kutilmaydi — tezroq) ishga tushadi; load esa barcha resurslar (rasm, shrift, stil) yuklanganda (kechroq). Odatda skriptni defer bilan yoki </body> oxirida ulasak — DOM allaqachon tayyor bo'ladi (Xato 1). React'da bu bevosita kam uchraydi (ilova bitta root'ga mount qilinadi), lekin storage React'da holatni saqlashda (useEffect ichida) juda ko'p ishlatiladi.

2.14. Fetch API — server bilan gaplashish (GET/POST/PUT/DELETE, async/await)

text
  FETCH — brauzerdan serverga HTTP so'rov (5–7 QISM'dagi REST API bilan bog'lanish):

  // GET — o'qish (Read):
  const res = await fetch("/api/tasks");         // so'rov yuboriladi (Promise qaytaradi)
  if (!res.ok) throw new Error(`HTTP ${res.status}`);  // ❗ 404/500 ni fetch O'ZI xato demaydi
  const data = await res.json();                 // javob tanasini JSON'ga aylantirish (yana await)

  // POST — yaratish (Create):
  const res = await fetch("/api/tasks", {
    method: "POST",
    headers: { "Content-Type": "application/json" },   // ❗ serverga "men JSON yubordim"
    body: JSON.stringify({ title: "Yangi vazifa" }),   // ❗ obyekt → string (JSON)
  });

  // PUT — yangilash (Update):   method:"PUT",  body: JSON.stringify(o'zgargan)
  // DELETE — o'chirish:         await fetch(`/api/tasks/${id}`, { method: "DELETE" });

  RESPONSE (javob) obyekti:
    res.ok       // true, agar status 200–299 (muvaffaqiyat)
    res.status   // 200, 404, 500...
    res.json()   // tanani JSON obyektga (Promise)   res.text() // matn sifatida

  ❗ fetch faqat TARMOQ uzilsa reject bo'ladi; 404/500 — res.ok=false, xato ATMAYDI → o'zingiz tekshiring
  ❗ AbortController — so'rovni BEKOR qilish (foydalanuvchi sahifadan chiqib ketsa):
    const c = new AbortController();
    fetch(url, { signal: c.signal });   c.abort();   // so'rov to'xtatiladi

Fetch API — brauzerdan serverga HTTP so'rov yuborishning zamonaviy standarti (eski XMLHttpRequest o'rnini bosgan). U Promise qaytaradi, shuning uchun async/await bilan qulay yoziladi (4-QISM). Bobning sarlavhasidagi "API (CRUD)" aynan shu: DOM CRUD'i sahifani o'zgartirsa, server CRUD'i ma'lumotni REST API orqali saqlaydi — GET (Read), POST (Create), PUT/PATCH (Update), DELETE. POST/PUT'da uchta narsa muhim: method, headers (Content-Type: application/json — serverga "men JSON yubordim" deb aytish), va body (JSON.stringify bilan obyektni matnga aylantirish). Javob Response obyekti: res.ok (200–299 bo'lsa true), res.status, res.json() (tanani obyektga aylantiruvchi yana bir Promise — yana await). Eng katta tuzoq: fetch faqat tarmoq uzilganda rad (reject) bo'ladi — 404/500 kabi server xatolarida fetch xato tashlamaydi, faqat res.ok false bo'ladi; shuning uchun har doim if (!res.ok) throw ... bilan qo'lda tekshirish kerak. AbortController — davom etayotgan so'rovni bekor qiladi (foydalanuvchi sahifani almashtirsa keraksiz so'rovni to'xtatish uchun; React'da useEffect tozalashida keng ishlatiladi). Bu — 5-QISM (Node/Express API) va 6-QISM (NestJS) da yozgan backend'ingizga frontend'dan ulanishning ko'prigi.

2.15. To'liq CRUD sikli: DOM + REST API birgalikda

text
  HAQIQIY ILOVA = ma'lumot SERVERDA + ko'rinish DOM'da. CRUD ikki tomonda birga yuradi:

  ┌──────────────┬───────────────────────────┬──────────────────────────────┐
  │  AMAL        │  SERVER (fetch — REST)    │  DOM (ko'rinish — 2.4)       │
  ├──────────────┼───────────────────────────┼──────────────────────────────┤
  │ Read (READ)  │ GET /api/tasks            │ ro'yxatni render qilish       │
  │ Create       │ POST /api/tasks           │ yangi <li> qo'shish           │
  │ Update       │ PUT /api/tasks/:id        │ <li> matnini/klassini o'zgart │
  │ Delete       │ DELETE /api/tasks/:id     │ <li> ni o'chirish             │
  └──────────────┴───────────────────────────┴──────────────────────────────┘

  ODATIY OQIM (Create):
   1. foydalanuvchi forma yuboradi (submit → preventDefault — 2.6)
   2. await fetch POST → server yangi yozuvni saqlaydi va {id, ...} qaytaradi
   3. server javobidan keyin ma'lumot massivini + DOM'ni yangilash (render)
   4. xato bo'lsa (res.ok=false yoki tarmoq) → foydalanuvchiga xabar (catch)

  ❗ E'TIBOR: bu yerda ENDI IKKI manba sinxron: server ↔ DOM (2.9 muammosi kuchayadi!)
     "loading", "xato", "bo'sh" holatlarini ham QO'LDA boshqarish kerak → React shu yerda yutadi

To'liq CRUD sikli — real ilovada ma'lumot serverda (ma'lumotlar bazasi — 7-QISM), ko'rinish esa DOM'da yashaydi, va CRUD ikki tomonda birga bajariladi: har bir amal avval fetch bilan serverga boradi, so'ng natijaga qarab DOM yangilanadi. Odatiy oqim: forma yuboriladi (preventDefault) → await fetch(POST) → server saqlab, yangi yozuvni (masalan id bilan) qaytaradi → shundan keyin ma'lumot massivi va DOM yangilanadi → xato bo'lsa catchda foydalanuvchiga xabar beriladi. Bu yerda 2.9'dagi sinxronlash muammosi yanada kuchayadi: endi faqat "massiv ↔ DOM" emas, balki "server ↔ massiv ↔ DOM" uch qatlam mos turishi kerak, ustiga "yuklanmoqda" (loading), "xato" (error), "bo'sh" (empty) holatlarini ham qo'lda boshqarish qo'shiladi. Bularning barchasini vanilla'da qo'lda ushlab turish — juda charchatadi. Aynan shuning uchun React va uning ma'lumot-olish kutubxonalari (masalan keyingi boblardagi yondashuvlar) bu holatlarni tizimli boshqaradi — imperativ DOM'ning og'rig'i bu yerda cho'qqisiga chiqadi.


3. Sintaksis — tez ma'lumotnoma

text
TANLASH 2.3-bob:  document.querySelector(".x") | querySelectorAll("li") | getElementById("id")
NAVIGATSIYA:    el.parentElement | el.children | el.closest(".x") | el.nextElementSibling
CREATE 2.4-bob:   document.createElement("li") | ul.append(li) | el.prepend/before/after
READ:           el.textContent | el.innerHTML (XSS!) | input.value
UPDATE:         el.textContent="..." | el.classList.add/remove/toggle("x") | el.style.color
ATRIBUT 2.5-bob:  el.setAttribute("href","#") | el.dataset.id | el.getAttribute("href")
DELETE:         el.remove() | parent.removeChild(el)
HODISA 2.6-bob:   el.addEventListener("click", e => {...}) | e.target | e.preventDefault()
FRAGMENT 2.8-bob: document.createDocumentFragment() | fragment.append(...) | ul.append(fragment)
MASSIVGA:       [...nodeList] yoki Array.from(nodeList)  // NodeList → Array (map/filter uchun)
QO'SHISH 2.11-bob:el.insertAdjacentHTML("beforeend", html) | el.cloneNode(true) | old.replaceWith(new)
BOM 2.12-bob:     location.href | location.pathname | history.pushState(s,"",url) | navigator.language
STORAGE 2.13-bob: localStorage.setItem(k,v) | getItem(k) | JSON.stringify/parse | sessionStorage
HAYOT SIKLI:    document.addEventListener("DOMContentLoaded", ...)  // DOM tayyor bo'lganda
FETCH 2.14-bob:   await fetch(url) | { method, headers, body: JSON.stringify(x) } | res.ok | res.json()

4. Batafsil kod namunalari

Misol 1 — Element tanlash va xavfsiz o'qish (2.3)

javascript
// Elementni "ushlab olamiz" (avval tanlash — har ishning 1-qadami)
const title = document.querySelector("h1");        // birinchi h1
const items = document.querySelectorAll(".item");  // barcha .item (NodeList)

// ❗ querySelector null qaytarishi mumkin — ishonchli kod tekshiradi
const banner = document.querySelector(".banner");
if (banner) {                                       // topilgan bo'lsa...
  banner.textContent = "Xush kelibsiz!";            // ...ishlatamiz
}

// NodeList ustida aylanish (forEach bor; map/filter uchun massivga aylantir)
items.forEach((el, i) => (el.textContent = `Element #${i + 1}`));
const titles = [...items].map(el => el.textContent); // [...] bilan massiv → map ishlaydi

Misol 2 — DOM CRUD: yaratish, qo'shish, o'chirish (2.4)

javascript
const ul = document.querySelector("#list");

// CREATE — uch qadam: yarat → to'ldir → ula
function addItem(text) {
  const li = document.createElement("li");          // 1. yarat (hali sahnada YO'Q)
  li.textContent = text;                            // 2. matnni qo'y (xavfsiz)
  li.classList.add("list-item");                    // 3. stil klassi
  ul.append(li);                                    // 4. daraxtga ula → endi ko'rinadi
  return li;
}

const first = addItem("Sut sotib olish");
addItem("Non sotib olish");

// UPDATE — mavjud elementni o'zgartirish
first.textContent = "Sut + qaymoq sotib olish";     // matnni almashtir
first.classList.toggle("done");                     // "done" klassini yoq/o'chir

// DELETE — o'zini o'chiradi
first.remove();                                     // birinchi element o'chdi

Misol 3 — innerHTML vs textContent va XSS xavfi (2.4, 14-QISM)

javascript
const box = document.querySelector("#box");
const userInput = '<img src=x onerror="alert(\'buzildi!\')">'; // zararli matn (foydalanuvchidan)

// ❌ XAVFLI — innerHTML matnni HTML sifatida bajaradi → XSS hujumi
box.innerHTML = userInput;        // <img> yuklanadi, onerror ishlaydi — kod bajarildi!

// ✅ XAVFSIZ — textContent matnni faqat MATN sifatida ko'rsatadi (tegni bajarmaydi)
box.textContent = userInput;      // ekranda literal matn ko'rinadi, kod ISHLAMAYDI

// ❗ Qoida: foydalanuvchi kiritgan har qanday narsani textContent bilan chiqaring
//    (innerHTML faqat O'ZINGIZ ishonadigan, statik HTML uchun)

Misol 4 — classList bilan holatni boshqarish (2.5)

javascript
const menu = document.querySelector(".menu");
const burger = document.querySelector(".burger");

// toggle — bor bo'lsa o'chiradi, yo'q bo'lsa qo'shadi (switch tugma uchun ideal)
burger.addEventListener("click", () => {
  menu.classList.toggle("open");                    // har bosishda ochiq/yopiq
  const isOpen = menu.classList.contains("open");   // hozir ochiqmi? (true/false)
  burger.setAttribute("aria-expanded", isOpen);     // a11y — ekran o'quvchiga xabar (1.9)
});
// ❗ Stilni CSS'da .menu.open { ... } qilib yozamiz — JS faqat klassni almashtiradi
//    (mas'uliyat ajratilgan: JS — mantiq, CSS — ko'rinish)

Misol 5 — Hodisalar va preventDefault (2.6)

javascript
const form = document.querySelector("#login-form");

form.addEventListener("submit", (event) => {
  event.preventDefault();             // ❗ sahifa qayta yuklanishini TO'XTAT (forma standarti)
  const email = form.querySelector("[name=email]").value;  // input qiymati
  if (!email.includes("@")) {
    alert("Email noto'g'ri");
    return;                           // davom etmaymiz
  }
  console.log("Yuborilmoqda:", email); // bu yerda fetch/axios bo'lardi (2.18)
});

Misol 6 — Event delegation (1 listener, ko'p bola — 2.6)

javascript
const list = document.querySelector("#todo-list");

// 100 ta tugmaga 100 ta listener O'RNIGA — otaga 1 ta (xotira/performance)
list.addEventListener("click", (event) => {
  // Qaysi bola bosildi? event.target bilan aniqlaymiz
  if (event.target.matches(".delete-btn")) {        // o'chirish tugmasimi?
    event.target.closest("li").remove();            // eng yaqin <li> ni o'chir
  }
  if (event.target.matches(".toggle-btn")) {        // bajarildi tugmasimi?
    event.target.closest("li").classList.toggle("done");
  }
});
// ❗ Yangi qo'shilgan <li>lar ham AVTOMATIK ishlaydi (listener otada — har doim bor)

Misol 7 — DocumentFragment bilan tez ro'yxat qurish (2.8)

javascript
const ul = document.querySelector("#big-list");
const data = Array.from({ length: 1000 }, (_, i) => `Mahsulot ${i + 1}`);

// ✅ TEZ — fragmentga to'plab, 1 marta DOM'ga ulash (1 reflow)
const fragment = document.createDocumentFragment();   // ko'rinmas idish (sahnada YO'Q)
for (const text of data) {
  const li = document.createElement("li");
  li.textContent = text;
  fragment.append(li);              // fragmentga — REFLOW YO'Q
}
ul.append(fragment);                // 1 marta haqiqiy DOM'ga → 1 reflow (2.7)

// ❌ SEKIN bo'lardi: for ichida har safar ul.append(li) → ~1000 reflow

Misol 8 — Layout thrashing va uni tuzatish (2.7)

javascript
const boxes = document.querySelectorAll(".box");

// ❌ YOMON — o'qish (offsetWidth) va yozishni ARALASHTIRISH → har safar reflow
boxes.forEach(box => {
  const w = box.offsetWidth;        // O'QISH → brauzer reflow'ni majburlaydi
  box.style.width = w + 10 + "px";  // YOZISH → keyingi o'qish yana reflow...
});

// ✅ YAXSHI — avval HAMMASINI o'qi, KEYIN hammasini yoz (reflow'lar ajratilgan)
const widths = [...boxes].map(box => box.offsetWidth);   // 1-faza: faqat o'qish
boxes.forEach((box, i) => (box.style.width = widths[i] + 10 + "px")); // 2-faza: faqat yozish

Misol 9 — To'liq imperativ "Vazifalar" ilovasi (2.9 og'rig'ini his qil)

javascript
// === Ma'lumot (state) — DOM'dan ALOHIDA yashaydi ===
let tasks = [];

const input = document.querySelector("#task-input");
const ul = document.querySelector("#task-list");
const counter = document.querySelector("#counter");
const empty = document.querySelector("#empty-msg");

// === HAR o'zgarishda QO'LDA chaqiriladigan "qayta chizish" funksiyasi ===
function render() {
  ul.innerHTML = "";                          // eski ro'yxatni tozalash (yana qurish uchun)
  const fragment = document.createDocumentFragment();
  tasks.forEach((task, i) => {
    const li = document.createElement("li");
    li.textContent = task.title;
    if (task.done) li.classList.add("done");
    const del = document.createElement("button");
    del.textContent = "🗑";
    del.dataset.index = i;                     // qaysi vazifa? (DOM↔ma'lumot bog'lash — 2.5)
    li.append(del);
    fragment.append(li);
  });
  ul.append(fragment);
  counter.textContent = `Jami: ${tasks.length}`;        // ✏️ hisoblagichni QO'LDA yangila
  empty.style.display = tasks.length ? "none" : "block"; // ✏️ "Bo'sh" xabarini QO'LDA boshqar
}

input.addEventListener("keydown", (e) => {
  if (e.key === "Enter" && input.value.trim()) {
    tasks.push({ title: input.value.trim(), done: false });
    input.value = "";
    render();                                  // ❗ o'zgardi → QO'LDA render chaqirish
  }
});

ul.addEventListener("click", (e) => {          // delegation (2.6)
  if (e.target.matches("button")) {
    tasks.splice(e.target.dataset.index, 1);   // ma'lumotdan o'chir
    render();                                  // ❗ yana QO'LDA render
  }
});
// ❗ DIQQAT: har o'zgarishda render() ni QO'LDA chaqiryapmiz. Unutsak — UI eskirib qoladi.
//    React'da bu render AVTOMATIK (state o'zgarsa — UI o'zi yangilanadi). Mana farq!

Misol 10 — Xuddi shu ilova React'da qanday ko'rinishini oldindan ko'rish (ko'prik)

jsx
// === Bu — KEYINGI boblardagi React (hozir tushunish shart emas, FARQNI ko'r) ===
function TaskApp() {
  const [tasks, setTasks] = useState([]);          // ma'lumot React'da yashaydi

  const add = (title) => setTasks([...tasks, { title, done: false }]); // faqat ma'lumotni o'zgartir
  const remove = (i) => setTasks(tasks.filter((_, idx) => idx !== i));

  // ❗ "render()" YO'Q — UI ma'lumotning funksiyasi (UI = f(state)). React o'zi yangilaydi:
  return (
    <div>
      <input onKeyDown={(e) => e.key === "Enter" && add(e.target.value)} />
      <ul>
        {tasks.map((task, i) => (
          <li key={i} className={task.done ? "done" : ""}>
            {task.title}
            <button onClick={() => remove(i)}>🗑</button>
          </li>
        ))}
      </ul>
      <p>Jami: {tasks.length}</p>                   {/* avtomatik yangilanadi */}
      {tasks.length === 0 && <p>Bo'sh</p>}          {/* shart — avtomatik */}
    </div>
  );
}
// ❗ Misol 9 da render() ni 2 marta QO'LDA chaqirdik + hisoblagich/xabarni qo'lda yangiladik.
//    Bu yerda — faqat tasks ni o'zgartiramiz, qolganini React qiladi. Mana shu — declarative.

Misol 11 — insertAdjacentHTML, cloneNode va replaceWith (2.11)

javascript
const ul = document.querySelector("#list");

// insertAdjacentHTML — mavjud ro'yxatni qayta qurmay, faqat yangi elementni qo'shish
// (innerHTML += dan afzal: eski <li>lardagi listenerlar saqlanadi, reflow kamroq)
const xavfsizNom = "Sut";                             // ishonchli/ekranlangan matn bo'lishi shart
ul.insertAdjacentHTML("beforeend", `<li>${xavfsizNom}</li>`);

// cloneNode — <template> ichidagi shablonni takrorlash (tez usul)
const tpl = document.querySelector("#row-template");  // <template id="row-template"><li>...</li></template>
const nusxa = tpl.content.firstElementChild.cloneNode(true); // true = bolalari bilan chuqur nusxa
nusxa.querySelector(".name").textContent = "Non";     // nusxani to'ldiramiz
ul.append(nusxa);

// replaceWith — bir elementni boshqasi bilan almashtirish (eski replaceChild o'rniga)
const eski = ul.querySelector("li");
const yangi = document.createElement("li");
yangi.textContent = "Almashtirildi";
eski.replaceWith(yangi);                              // eski o'rnida endi yangi turadi

Misol 12 — localStorage bilan holatni saqlash (2.13)

javascript
const SAVAT_KALIT = "savat";

// O'qish — brauzerda saqlangan savatni tiklash (yo'q bo'lsa bo'sh massiv)
function savatniYukla() {
  const xom = localStorage.getItem(SAVAT_KALIT);      // string yoki null
  return xom ? JSON.parse(xom) : [];                  // ❗ null himoyasi + JSON.parse
}

// Yozish — obyekt/massivni saqlashdan oldin string'ga aylantirish shart
function savatniSaqla(savat) {
  localStorage.setItem(SAVAT_KALIT, JSON.stringify(savat)); // ❗ obyekt → JSON string
}

let savat = savatniYukla();                           // sahifa ochilganda tiklaymiz
savat.push({ nom: "Sut", narx: 12000 });
savatniSaqla(savat);                                  // har o'zgarishda saqlaymiz
// ❗ localStorage FAQAT string saqlaydi; token/parol saqlash xavfli (XSS — 14-QISM)

Misol 13 — Fetch bilan REST API: GET va POST, xato boshqaruvi (2.14)

javascript
const API = "/api/tasks";

// READ (GET) — ro'yxatni serverdan olish
async function tasksniOl() {
  const res = await fetch(API);
  if (!res.ok) throw new Error(`HTTP ${res.status}`); // ❗ 404/500 ni O'ZIMIZ tekshiramiz
  return res.json();                                  // javob tanasi → obyekt (Promise)
}

// CREATE (POST) — yangi vazifa yaratish
async function taskQosh(title) {
  const res = await fetch(API, {
    method: "POST",
    headers: { "Content-Type": "application/json" },  // ❗ "men JSON yubordim"
    body: JSON.stringify({ title, done: false }),     // ❗ obyekt → JSON string
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();                                  // server qaytargan yangi yozuv (id bilan)
}

// Ishlatish — xato boshqaruvi bilan (foydalanuvchiga bildirish)
(async () => {
  try {
    const yangi = await taskQosh("Kitob o'qish");     // serverga yozamiz
    const barchasi = await tasksniOl();               // yangilangan ro'yxatni olamiz
    console.log("Yaratildi:", yangi, "Jami:", barchasi.length);
  } catch (err) {
    console.error("So'rov muvaffaqiyatsiz:", err.message); // tarmoq yoki server xatosi
  }
})();

Misol 14 — To'liq CRUD: DOM + REST API + AbortController (2.14, 2.15)

javascript
const API = "/api/tasks";
const ul = document.querySelector("#task-list");
const status = document.querySelector("#status");     // "yuklanmoqda / xato" xabari uchun

let tasks = [];                                        // lokal nusxa (server ↔ DOM oralig'ida)

// Markazlashgan render — server ↔ DOM sinxronini bitta joyda ushlash (2.9, 2.15)
function render() {
  ul.innerHTML = "";
  const fragment = document.createDocumentFragment();
  tasks.forEach((t) => {
    const li = document.createElement("li");
    li.textContent = t.title;                          // XSS'siz (textContent — 2.4)
    if (t.done) li.classList.add("done");
    const del = document.createElement("button");
    del.textContent = "🗑";
    del.dataset.id = t.id;                             // qaysi yozuv? (DOM↔ma'lumot — 2.5)
    li.append(del);
    fragment.append(li);
  });
  ul.append(fragment);                                 // 1 marta DOM'ga (2.8)
}

// READ — ilova boshida ro'yxatni yuklash (loading/error holatlari bilan)
async function yukla() {
  status.textContent = "Yuklanmoqda...";               // ✏️ loading holatini QO'LDA
  try {
    const res = await fetch(API);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    tasks = await res.json();
    status.textContent = tasks.length ? "" : "Ro'yxat bo'sh"; // ✏️ empty holatini QO'LDA
    render();                                          // ✏️ DOM'ni QO'LDA yangilash
  } catch (err) {
    status.textContent = "Xato: " + err.message;       // ✏️ error holatini QO'LDA
  }
}

// DELETE — server + DOM (delegation orqali, 2.6)
ul.addEventListener("click", async (e) => {
  if (!e.target.matches("button")) return;
  const id = e.target.dataset.id;
  try {
    const res = await fetch(`${API}/${id}`, { method: "DELETE" });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    tasks = tasks.filter((t) => String(t.id) !== id);  // ✏️ massivdan o'chirish
    render();                                          // ✏️ DOM'ni yangilash
  } catch (err) {
    status.textContent = "O'chirishda xato: " + err.message;
  }
});

// AbortController — sahifadan chiqilsa davom etayotgan so'rovni bekor qilish
const controller = new AbortController();
fetch(API, { signal: controller.signal });
window.addEventListener("beforeunload", () => controller.abort()); // keraksiz so'rovni to'xtat

yukla();
// ❗ DIQQAT: loading/error/empty + server↔massiv↔DOM sinxronini HAMMASINI qo'lda ushladik.
//    React va uning ma'lumot-olish yondashuvlari aynan shu holatlarni tizimli boshqaradi 2.15-bob.

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

1) Foydalanuvchi kiritgan matnni chiqarish

text
❌ box.innerHTML = userInput   (XSS xavfi — kod bajariladi — Misol 3)
✅ box.textContent = userInput (faqat matn sifatida — xavfsiz)

2) Ko'p element qo'shish

text
❌ for ichida ul.append(li) 1000 marta (1000 reflow — sekin)
✅ DocumentFragment'ga to'plab 1 marta append (1 reflow — Misol 7)

3) Ko'p bolaga hodisa

text
❌ har <li> ga alohida addEventListener (xotira, yangi li ishlamaydi)
✅ otaga 1 ta listener + event delegation (Misol 6)

4) querySelector natijasi

text
❌ document.querySelector(".x").textContent (element yo'q bo'lsa — crash)
✅ const el = querySelector(".x"); if (el) el.textContent = ... (Misol 1)

5) Stilni boshqarish

text
❌ el.style.color = "red" (ko'rinish JS'ga aralashib ketadi)
✅ el.classList.toggle("active") + CSS'da .active{} (mas'uliyat ajratilgan — Misol 4)

6) O'qish/yozishni aralashtirish

text
❌ tsiklda offsetWidth o'qib, darrov style yozish (layout thrashing — Misol 8)
✅ avval hamma o'qish, keyin hamma yozish (ikki fazaga ajrat)

7) Fetch javobini tekshirish

text
❌ const data = await (await fetch(url)).json()  (404/500 sezilmaydi — buzuq ma'lumot)
✅ if (!res.ok) throw new Error(res.status); keyin res.json() (Misol 13)

8) Obyektni localStorage'ga saqlash

text
❌ localStorage.setItem("savat", savatObyekt)   ("[object Object]" saqlanadi — buziladi)
✅ localStorage.setItem("savat", JSON.stringify(savatObyekt)) (Misol 12)

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — Uncaught TypeError: Cannot read properties of null (reading 'textContent')

Sababi: querySelector element topmadi (null), unga .textContent qildik. Ko'pincha skript HTML'dan oldin ishga tushgan (element hali yo'q), yoki selektor xato. Yechimi: skriptni </body> oxirida yoki defer bilan ulang; selektorni tekshiring; natijani if (el) bilan tekshiring (Misol 1).

Xato 2 — Yangi qo'shilgan elementga hodisa ishlamaydi

Sababi: addEventListenerni faqat mavjud elementlarga qo'ygansiz; keyin qo'shilganlarda listener yo'q. Yechimi: event delegation — otaga listener qo'ying, e.target bilan ajrating (2.6, Misol 6).

Xato 3 — el.style.background-color ishlamaydi

Sababi: style xususiyatlari camelCase bo'lishi kerak. Yechimi: el.style.backgroundColor = "..." (yoki el.style.setProperty("background-color", "...")).

Xato 4 — Sahifa forma yuborilgach qayta yuklanib ketadi

Sababi: forma submit'ida event.preventDefault() chaqirilmagan (brauzer standarti — sahifani qayta yuklash). Yechimi: form.addEventListener("submit", e => { e.preventDefault(); ... }) (Misol 5).

Xato 5 — querySelectorAll(...).map is not a function

Sababi: querySelectorAll NodeList qaytaradi — massiv emas, map yo'q. Yechimi: [...nodeList].map(...) yoki Array.from(nodeList).map(...) 2.3-bob.

Xato 6 — Sahifa ko'p element bilan qotib qoladi (sekin)

Sababi: tsiklda DOM'ga ko'p marta tegish (har safar reflow — 2.7). Yechimi: DocumentFragment yoki string to'plab bir marta qo'llash (Misol 7); o'qish/yozishni ajratish (Misol 8).

Xato 7 — UI ma'lumotga mos kelmaydi (ekranda 3 ta, ma'lumotda 2 ta)

Sababi: ma'lumotni o'zgartirib, DOM'ni (yoki uning bir qismini) yangilashni unutgansiz (2.9 — sinxronlash muammosi). Yechimi: vanilla'da — markazlashgan render() funksiyasi (Misol 9); to'g'ri yechim — React (Misol 10).

Xato 8 — fetch 404/500 da ham "ishladi" deb hisoblanadi (buzuq ma'lumot)

Sababi: fetch faqat tarmoq uzilganda rad bo'ladi; server 404/500 qaytarsa Promise baribir bajariladi va .json() xato tanani o'qiydi. Yechimi: har doim if (!res.ok) throw new Error(res.status) bilan qo'lda tekshirish, so'ng res.json() (2.14, Misol 13).

Xato 9 — localStorageda obyekt "[object Object]" bo'lib buzilib qoladi

Sababi: localStorage faqat matn saqlaydi; obyektni to'g'ridan berganda u avtomatik String() bilan "[object Object]"ga aylanadi. Yechimi: yozishda JSON.stringify, o'qishda JSON.parse (null himoyasi bilan — 2.13, Misol 12).


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • JS DOM 2.16-bob: bu bob uning frontend rakursidagi chuqur takrori.
  • Brauzer rendering 0.5-bob: critical rendering path shu yerda amalda.
  • HTML/CSS (1-QISM): DOM — HTML'ning jonli ko'rinishi; classList — CSS bilan ko'prik.
  • Node/Express API (5-QISM), NestJS (6-QISM): fetch shu backend'ga frontend'dan ulanadi (REST CRUD — 2.14, 2.15).
  • Ma'lumotlar bazasi (7-QISM): server CRUD'i oxir-oqibat DB'ga yozadi; DOM — uning ko'rinishi.
  • Async/await, Promise (4-QISM): fetch va res.json() — Promise; xato boshqaruvi try/catch.
  • React (11.2+): Virtual DOM — bu bobdagi fragment/reflow muammolarini avtomatlashtiradi; ma'lumot-olish (useEffect + fetch) — 2.14/2.15 ning React versiyasi.
  • Routing: history.pushState 2.12-bob — SPA va React Router asosi.
  • Performance 11.11-bob: reflow/repaint — React optimizatsiyasining asosi.
  • Forma 11.10-bob: value, submit, preventDefault — React'da controlled input asosi.
  • Xavfsizlik (14-QISM): innerHTML/XSS (2.4, 2.11), localStorage'da token saqlash xavfi 2.13-bob — React dangerouslySetInnerHTML bilan bog'liq.

8. Eng yaxshi amaliyotlar (best practices)

  • textContent standart, innerHTML ehtiyotkorlik (foydalanuvchi matnini hech qachon innerHTML'ga — XSS — Misol 3).
  • querySelector natijasini tekshirish (null bo'lishi mumkin — Misol 1).
  • Stilni classList bilan (ko'rinish CSS'da; JS faqat klass almashtiradi — Misol 4).
  • Event delegation (ko'p bolaga 1 listener — xotira, dinamik elementlar — Misol 6).
  • DOM'ga teginishni minimallashtirish (fragment, string to'plab; tsiklda append qilmaslik — Misol 7).
  • O'qish/yozishni ajratish (layout thrashing'dan qochish — Misol 8).
  • Skriptni defer bilan yoki body oxirida (DOM tayyor bo'lgach ishlasin — Xato 1).
  • fetch javobini har doim res.ok bilan tekshirish (404/500 xato tashlamaydi — Misol 13).
  • fetchni try/catchga o'rash va loading/error/empty holatlarni ko'rsatish (Misol 14).
  • localStoragega obyektni JSON.stringify bilan yozish (faqat string saqlaydi — Misol 12); token/parol saqlamaslik (XSS — 14-QISM).
  • insertAdjacentHTMLni innerHTML += o'rniga (konteynerni qayta qurmaydi, listenerlar saqlanadi — 2.11).
  • Ma'lumotni yagona manba qilish (UI — ma'lumotning aksi; markazlashgan render — bu fikr React'ga olib boradi — 2.9, 2.10).

9. Amaliy loyiha: "Vanilla DOM bilan Savatcha (imperativ)"

Bu loyiha — ataylab vanilla JS'da (React'siz). Maqsad — imperativ DOM'ning og'rig'ini o'z qo'lingiz bilan his qilish, toki keyingi bobda React sizni "ozod qilganda" uning qadrini bilasiz.

Maqsad

Faqat HTML + CSS + vanilla JS bilan ishlaydigan onlayn do'kon savatchasi yarating: mahsulot qo'shish, sonini o'zgartirish, o'chirish, umumiy narxni hisoblash.

Talablar (requirements)

  1. Mahsulotlar ro'yxati: kamida 5 ta mahsulot (nom, narx, rasm/emoji) — massivdan DOM'ga chiqarish (Misol 7 — fragment).
  2. Savatga qo'shish: "Qo'shish" tugmasi mahsulotni savatga qo'shsin (delegation — Misol 6).
  3. Son boshqaruvi: savatda har mahsulot uchun + / − tugmalari (son 0 bo'lsa — o'chirilsin).
  4. O'chirish: savatdan mahsulotni butunlay o'chirish ().
  5. Umumiy narx: har o'zgarishda "Jami: X so'm" avtomatik yangilansin.
  6. Bo'sh holat: savat bo'sh bo'lsa "Savat bo'sh" xabari ko'rsatilsin.
  7. Markazlashgan render: barcha o'zgarishlar bitta renderCart() funksiyasidan o'tsin (Misol 9 uslubi).
  8. XSS himoyasi: mahsulot nomini textContent bilan chiqarish (Misol 3).
  9. Performance: ro'yxatni fragment bilan qurish; tsiklda to'g'ridan append qilmaslik (Misol 7).
  10. a11y: tugmalarga aria-label; klaviatura bilan ham ishlasin 1.9-bob.
  11. Doimiylik: savat localStorageda saqlansin (JSON.stringify/parse), sahifa qayta yuklanganda tiklansin (2.13, Misol 12).
  12. (ixtiyoriy) API: agar backend bo'lsa, savatni fetch bilan serverga yozib/o'qib ko'ring; res.ok va try/catch bilan xatoni boshqaring (2.14, Misol 13–14).

Maslahatlar (hint)

  • Ma'lumotni (savat) bitta massivda saqlang; DOM — uning aksi (har o'zgarishda renderCart()).
  • Har bir o'zgarishdan keyin renderCart() ni qo'lda chaqirishni unutmang — va aynan shu "unutmaslik kerakligi" React'ning sababi 2.9-bob.
  • dataset.id bilan DOM tugmasini ma'lumotga bog'lang (qaysi mahsulot bosildi).
  • Son va narxni har safar massivdan qayta hisoblang (DOM'dan o'qimang — ma'lumot — yagona manba).
  • Sanang: ilova oxirida renderCart() ni necha marta qo'lda chaqirdingiz? Har biri — React qiladigan ish.

"Tayyor" mezonlari (acceptance criteria)

  • Mahsulotlar massivdan DOM'ga chiqadi (fragment bilan).
  • Savatga qo'shish/o'chirish ishlaydi (delegation bilan).
  • +/− son boshqaruvi (0 da o'chadi).
  • Umumiy narx har o'zgarishda to'g'ri yangilanadi.
  • Savat bo'sh bo'lsa "Bo'sh" xabari chiqadi.
  • Barcha o'zgarish markazlashgan renderCart() dan o'tadi.
  • Mahsulot nomi textContent bilan (XSS yo'q).
  • Tsiklda to'g'ridan-to'g'ri append yo'q (fragment ishlatilgan).
  • UI hech qachon ma'lumotga zid kelmaydi (sinxron).
  • Savat localStorageda saqlanadi va sahifa qayta yuklanganda tiklanadi.

Bu loyiha — mustaqil amaliyot uchun. Yuqoridagi talab va maslahatlardan foydalanib, savatchani o'zingiz to'liq yozib ko'ring; Misol 9 dagi markazlashgan render() uslubi asosiy suyanchiq bo'ladi.


10. Xulosa va keyingi bobga ko'prik

Bu bobda frontend'ning poydevori — brauzer va DOM — ni chuqur takrorladik:

  • Critical Rendering Path (HTML→DOM, CSS→CSSOM, render tree, layout, paint — 2.1); DOM daraxti va node turlari 2.2-bob.
  • Tanlash (querySelector — 2.3); CRUD (create/read/update/delete — 2.4); class/style/dataset 2.5-bob; hodisalar (delegation, bubbling — 2.6).
  • Reflow/repaint (nega qo'lda DOM sekin — 2.7); DocumentFragment (batching — 2.8).
  • Va eng muhimi — imperativ DOM'ning tub muammosi (state ↔ UI ni qo'lda sinxronlash — 2.9) va undan chiqish yo'li: deklarativ yondashuv, UI = f(state) 2.10-bob.
  • Qo'shimcha manipulyatsiya (insertAdjacentHTML, cloneNode, replaceWith — 2.11); BOM (window, location, history, navigator — 2.12); Web Storage va sahifa hayot sikli (localStorage, DOMContentLoaded — 2.13).
  • Fetch API (GET/POST/PUT/DELETE, res.ok, async/await, AbortController — 2.14) va to'liq CRUD sikli (DOM + REST API birga; loading/error/empty holatlar — 2.15) — bobning "API (CRUD)" qismi.

Endi siz vanilla DOM bilan har narsani qila olasiz — lekin har o'zgarishda render() ni qo'lda chaqirish, qaysi joyni yangilashni eslab qolish, sinxronlashni qo'lda ushlab turishning og'rig'ini his qildingiz. Bu og'riq tasodifiy emas — u butun bir kutubxonaning tug'ilish sababi.

Keyingi bob — 11.2-bob: React kirish — JSX, komponentlar, props. Endi avtomat qo'g'irchoqchini ishga solamiz. React'ning markaziy g'oyasi — UI'ni mustaqil, qayta ishlatiladigan bo'laklar (komponentlar)ga bo'lish va ularni JSX (JavaScript ichida HTML'ga o'xshash sintaksis) bilan deklarativ tasvirlash. Siz render() ni qo'lda chaqirishni unutasiz — chunki React buni state o'zgarganda avtomatik qiladi. "Qanday" emas, "nima" deb fikrlashni boshlaymiz.


Foydalanilgan rasmiy/ishonchli manbalar

  • MDN Web Docs — Document Object Model (DOM), Document.querySelector, Node, Element, DocumentFragment
  • MDN Web Docs — "Introduction to events", Event delegation, EventTarget.addEventListener
  • MDN Web Docs — Fetch API, Response, Request, AbortController; Web Storage API (localStorage, sessionStorage)
  • MDN Web Docs — Browser Object Model: Window, Location, History, Navigator
  • web.dev (Google) — "Critical Rendering Path", "Avoid large, complex layouts and layout thrashing"
  • HTML Living Standard (WHATWG) — DOM, events, history.pushState, script defer
  • React rasmiy hujjati (react.dev) — "Thinking in React", "Reacting to Input with State" (deklarativ falsafa)
Ulashish:Telegram'da

O'qiganingizni mustahkamlang

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
DOM API va CRUD — brauzerda HTML/CSS/JS takrori (11.1-bob) — IlmHamroh