WisarWisar
Dasturlash kitobi/11-QISM — React39 daqiqa

11.1-bob: Brauzerda HTML/CSS/JS takrori va DOM API (CRUD)

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

   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'yma — 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'lumotingni 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 (readwriteread) 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. localStoragedoimiy (brauzer yopilib qayta ochilsa ham qoladi), sessionStoragevaqtinchalik (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'zing tekshir
   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 chiqar
//    (innerHTML faqat O'ZING 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 tozala (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? (DOMma'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? (DOMma'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 + servermassivDOM 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 (HTMLDOM, CSSCSSOM, 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)

Izohlar (0)

Izoh yozish uchun kiring.

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