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)
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:nonebu 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
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)
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) vaquerySelectorAll(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)querySelectorelement topmasanullqaytaradi — to'g'ridan-to'g'ri.textContentqilsangizCannot read properties of nullxatosi (2.6 xatolar); (2)querySelectorAllnatijasi NodeList — massiv emas,forEachbor lekinmap/filteryo'q (kerak bo'lsa[...nodeList]yokiArray.frombilan massivga aylantiriladi — 2.7).
2.4. DOM CRUD — yaratish, o'zgartirish, o'chirish
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 usulDOM 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'ldirishappend(yokiprepend/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 qachoninnerHTMLga 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
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-coloremas). Atribut:setAttribute/getAttribute/removeAttribute.dataset(data-*) — o'zingizning maxsus ma'lumotingizni HTML elementiga "yopishtirish" usuli (masalandata-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
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 funksiyaeventobyektini 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 bosilganinievent.targetorqali 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,onClickprop) — 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
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 reflowReflow 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 iteratsiyadaappend), 1000 marta reflow bo'ladi — sahifa qotadi. Yechim — o'zgarishlarni to'plab, DOM'ga bir marta tegish (string to'plabinnerHTML, 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)
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)
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
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
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) vareplaceChild(eski) — mavjud elementni boshqasi bilan almashtiradi.insertAdjacentHTMLhaminnerHTMLkabi 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)
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
windowturadi — u brauzerdagi global obyekt: har bir global o'zgaruvchi, funksiya, hattodocumentham aslidawindowning xususiyati (window.document),setTimeouthamwindow.setTimeout.location— joriy URL bilan ishlash (href,pathname,search,hash;location.href = "..."bilan boshqa sahifaga o'tish).history— brauzer navigatsiya tarixi; ayniqsahistory.pushStatemuhim: 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) vascreen(monitor o'lchami) — muhit haqida ma'lumot. BOM standartlashtirilmagan (brauzerlar biroz farq qiladi), lekinlocation/historyni bilish — routing va autentifikatsiya (redirect) uchun shart.
2.13. localStorage, sessionStorage va sahifa hayot sikli (DOMContentLoaded vs load)
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 hamsetItem/getItem/removeItem/clearbilan ishlaydi. Muhim cheklov: faqat matn (string) saqlaydi — obyekt yoki massivni saqlash uchunJSON.stringifybilan yozib,JSON.parsebilan 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:DOMContentLoadedhodisasi HTML tahlil qilinib DOM tayyor bo'lganda (rasm/stil kutilmaydi — tezroq) ishga tushadi;loadesa barcha resurslar (rasm, shrift, stil) yuklanganda (kechroq). Odatda skriptnideferbilan 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 (useEffectichida) juda ko'p ishlatiladi.
2.14. Fetch API — server bilan gaplashish (GET/POST/PUT/DELETE, async/await)
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'xtatiladiFetch API — brauzerdan serverga HTTP so'rov yuborishning zamonaviy standarti (eski
XMLHttpRequesto'rnini bosgan). U Promise qaytaradi, shuning uchunasync/awaitbilan 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), vabody(JSON.stringifybilan obyektni matnga aylantirish). JavobResponseobyekti:res.ok(200–299 bo'lsatrue),res.status,res.json()(tanani obyektga aylantiruvchi yana birPromise— yanaawait). Eng katta tuzoq:fetchfaqat tarmoq uzilganda rad (reject) bo'ladi — 404/500 kabi server xatolaridafetchxato tashlamaydi, faqatres.okfalsebo'ladi; shuning uchun har doimif (!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'dauseEffecttozalashida 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
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 yutadiTo'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
fetchbilan serverga boradi, so'ng natijaga qarab DOM yangilanadi. Odatiy oqim: forma yuboriladi (preventDefault)await fetch(POST)server saqlab, yangi yozuvni (masalanidbilan) qaytaradi shundan keyin ma'lumot massivi va DOM yangilanadi xato bo'lsacatchda 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
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)
// 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 ishlaydiMisol 2 — DOM CRUD: yaratish, qo'shish, o'chirish (2.4)
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'chdiMisol 3 — innerHTML vs textContent va XSS xavfi (2.4, 14-QISM)
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)
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)
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)
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)
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 reflowMisol 8 — Layout thrashing va uni tuzatish (2.7)
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 yozishMisol 9 — To'liq imperativ "Vazifalar" ilovasi (2.9 og'rig'ini his qil)
// === 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)
// === 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)
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 turadiMisol 12 — localStorage bilan holatni saqlash (2.13)
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)
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)
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
box.innerHTML = userInput (XSS xavfi — kod bajariladi — Misol 3)
box.textContent = userInput (faqat matn sifatida — xavfsiz)2) Ko'p element qo'shish
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
har <li> ga alohida addEventListener (xotira, yangi li ishlamaydi)
otaga 1 ta listener + event delegation (Misol 6)4) querySelector natijasi
document.querySelector(".x").textContent (element yo'q bo'lsa — crash)
const el = querySelector(".x"); if (el) el.textContent = ... (Misol 1)5) Stilni boshqarish
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
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
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
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):
fetchshu 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):
fetchvares.json()— Promise; xato boshqaruvitry/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.pushState2.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
dangerouslySetInnerHTMLbilan bog'liq.
8. Eng yaxshi amaliyotlar (best practices)
textContentstandart,innerHTMLehtiyotkorlik (foydalanuvchi matnini hech qachon innerHTML'ga — XSS — Misol 3).querySelectornatijasini tekshirish (nullbo'lishi mumkin — Misol 1).- Stilni
classListbilan (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
deferbilan yoki body oxirida (DOM tayyor bo'lgach ishlasin — Xato 1). fetchjavobini har doimres.okbilan tekshirish (404/500 xato tashlamaydi — Misol 13).fetchnitry/catchga o'rash va loading/error/empty holatlarni ko'rsatish (Misol 14).localStoragega obyektniJSON.stringifybilan yozish (faqat string saqlaydi — Misol 12); token/parol saqlamaslik (XSS — 14-QISM).insertAdjacentHTMLniinnerHTML +=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)
- Mahsulotlar ro'yxati: kamida 5 ta mahsulot (nom, narx, rasm/emoji) — massivdan DOM'ga chiqarish (Misol 7 — fragment).
- Savatga qo'shish: "Qo'shish" tugmasi mahsulotni savatga qo'shsin (delegation — Misol 6).
- Son boshqaruvi: savatda har mahsulot uchun
+/−tugmalari (son 0 bo'lsa — o'chirilsin). - O'chirish: savatdan mahsulotni butunlay o'chirish ().
- Umumiy narx: har o'zgarishda "Jami: X so'm" avtomatik yangilansin.
- Bo'sh holat: savat bo'sh bo'lsa "Savat bo'sh" xabari ko'rsatilsin.
- Markazlashgan render: barcha o'zgarishlar bitta
renderCart()funksiyasidan o'tsin (Misol 9 uslubi). - XSS himoyasi: mahsulot nomini
textContentbilan chiqarish (Misol 3). - Performance: ro'yxatni fragment bilan qurish; tsiklda to'g'ridan append qilmaslik (Misol 7).
- a11y: tugmalarga
aria-label; klaviatura bilan ham ishlasin 1.9-bob. - Doimiylik: savat
localStorageda saqlansin (JSON.stringify/parse), sahifa qayta yuklanganda tiklansin (2.13, Misol 12). - (ixtiyoriy) API: agar backend bo'lsa, savatni
fetchbilan serverga yozib/o'qib ko'ring;res.okvatry/catchbilan 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.idbilan 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
textContentbilan (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, scriptdefer - 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!