React rendering qanday ishlaydi — reconciliation, diffing
Muammodan boshlaylik
Uchta savol, javobini bilasizmi?
function App() {
const [son, setSon] = useState(0);
return (
<>
<button onClick={() => setSon(son + 1)}>{son}</button>
<Sarlavha /> {/* props yo'q, hech narsa o'zgarmaydi */}
</>
);
}
- Tugma bosilganda
<Sarlavha />qayta render bo'ladimi? — Ha. Props bo'lmasa ham - "Render" — DOM ni o'zgartirish degani mi? — Yo'q.
- Tab almashtirilganda nega forma qiymatlari ba'zan yo'qoladi, ba'zan qoladi?
Performance optimizatsiyasini boshlashdan oldin — React aslida nima qilishini tushunish kerak. Aks holda memo va useMemo ni "har ehtimolga qarshi" hamma joyga sochib, kodni murakkablashtirasiz va tezlikda deyarli hech narsa yutmaysiz.
Render nima
React da ekranni yangilash uch bosqichda bo'ladi:
1. TRIGGER 2. RENDER 3. COMMIT
state o'zgardi → komponent funksiyalari → DOM ga faqat
(setState) chaqiriladi, yangi JSX farqlar yoziladi
daraxti yasaladi,
eskisi bilan solishtiriladi
1. Trigger — nima render ni boshlaydi
- Komponentning o'z state i o'zgardi (
setState,dispatch) - Ota-ona komponent render bo'ldi
- Ishlatilayotgan Context qiymati o'zgardi
- Tashqi store (Zustand, Redux) dagi tanlangan qiymat o'zgardi
[!INFO] Props o'zgarishi — alohida trigger emas. Props faqat ota-ona render bo'lganda o'zgaradi, va ota-ona render bo'lganda bola props o'zgarganmi yoki yo'qmi — baribir render bo'ladi. Bu — eng ko'p uchraydigan noto'g'ri tushuncha.
2. Render — komponentni chaqirish
"Render" — React ning komponent funksiyangizni chaqirishi:
function Sarlavha() {
console.log('Sarlavha render'); // har renderda chiqadi
return <h1>DevDocs</h1>;
}
Funksiya yangi JSX qaytaradi — bu Virtual DOM: oddiy JavaScript obyektlari daraxti (1-dars):
{ type: 'h1', props: { children: 'DevDocs' } }
Render — arzon: obyektlar yaratish va solishtirish. U haqiqiy DOM ga tegmaydi.
3. Commit — DOM ni yangilash
React yangi daraxtni eskisi bilan solishtiradi va faqat farqlarni DOM ga yozadi. Agar <h1>DevDocs</h1> o'zgarmagan bo'lsa — DOM ga hech narsa yozilmaydi.
Shuning uchun Sarlavha ning qayta render bo'lishi o'z-o'zidan muammo emas: funksiya chaqirildi, natija bir xil, DOM tegilmadi.
Reconciliation — solishtirish
Ikki daraxtni to'liq solishtirish algoritmik jihatdan juda qimmat (O(n³)). React ikki oddiy taxmin bilan uni chiziqli (O(n)) qiladi.
1-taxmin: turi o'zgarsa — hammasi yangidan
// oldin
<div>
<Hisoblagich />
</div>
// keyin
<section>
<Hisoblagich />
</section>
div → section: tur boshqa. React eski daraxtni butunlay yo'q qiladi (unmount) va yangisini noldan yaratadi. Hisoblagich ning state i yo'qoladi, garchi u o'zi o'zgarmagan bo'lsa ham.
Bir xil tur bo'lsa — DOM elementi saqlanadi, faqat o'zgargan atributlar yangilanadi:
<div className="eski" /> → <div className="yangi" /> // faqat className o'zgaradi
2-taxmin: ro'yxatda key bilan
// oldin // keyin (boshiga qo'shildi)
<li>Ali</li> <li>Sardor</li>
<li>Vali</li> <li>Ali</li>
<li>Vali</li>
key siz React tartib bo'yicha solishtiradi: 1-element "Ali" → "Sardor" (o'zgardi), 2-element "Vali" → "Ali" (o'zgardi), 3-element yangi. Hammasi qayta yoziladi.
key bilan — elementlar shaxsi bo'yicha:
<li key="s">Sardor</li> // yangi — qo'shiladi
<li key="a">Ali</li> // mavjud — tegilmaydi
<li key="v">Vali</li> // mavjud — tegilmaydi
Shuning uchun key barqaror va noyob bo'lishi kerak, index emas (27-dars).
State qayerda yashaydi
Muhim tushuncha: state komponent funksiyasida emas, daraxtdagi joyida yashaydi. React uni "daraxtning shu pozitsiyasidagi shu turdagi komponent" bilan bog'laydi.
function App() {
const [admin, setAdmin] = useState(false);
return (
<div>
{admin ? <Forma rol="admin" /> : <Forma rol="mehmon" />}
</div>
);
}
Ikkala holatda ham div ning birinchi bolasi — Forma. Tur bir xil, joy bir xil → React uni bir xil komponent deb hisoblaydi → state saqlanadi. Admin/mehmon almashganda forma maydonlari tozalanmaydi.
Darsning boshidagi 3-savol javobi shu. Ataylab qayta yaratish kerak bo'lsa — key:
<Forma key={admin ? 'admin' : 'mehmon'} rol={admin ? 'admin' : 'mehmon'} />
key o'zgardi → React buni boshqa komponent deb hisoblaydi → eskisini unmount, yangisini mount → state toza.
// Profil sahifasi — foydalanuvchi o'zgarganda barcha state yangilansin
<ProfilTahrir key={userId} userId={userId} />
function Ota() {
function Bola() { return <input />; } // ❌ har renderda YANGI funksiya
return <Bola />;
}
[!WARNING] Komponentni boshqa komponent ichida e'lon qilmang. Har renderda
Bola— yangi funksiya, ya'ni yangi tur. React uni har safar unmount va mount qiladi: input fokusni va qiymatni yo'qotadi, effektlar qayta ishga tushadi. Komponentlarni har doim modul darajasida e'lon qiling.
Bola komponentlar qayta render bo'lishi
function App() {
const [son, setSon] = useState(0);
return (
<>
<button onClick={() => setSon(son + 1)}>{son}</button>
<KattaRoyxat /> {/* 1000 ta element */}
</>
);
}
Tugma bosilganda KattaRoyxat va uning 1000 ta bolasi qayta render bo'ladi. Odatda bu ham tez (millisekundlar). Lekin sekin bo'lsa — yechimlar:
1. State ni pastga tushirish
function App() {
return (
<>
<Hisoblagich /> {/* state shu yerda */}
<KattaRoyxat /> {/* endi render bo'lmaydi */}
</>
);
}
function Hisoblagich() {
const [son, setSon] = useState(0);
return <button onClick={() => setSon(son + 1)}>{son}</button>;
}
State faqat uni ishlatadigan komponentda. Eng oddiy va eng samarali optimizatsiya.
2. children orqali uzatish
function Scroll({ children }) {
const [y, setY] = useState(0);
// ... scroll ni kuzatish
return <div data-y={y}>{children}</div>;
}
<Scroll>
<KattaRoyxat /> {/* App da yaratilgan — Scroll render bo'lsa ham qayta render yo'q */}
</Scroll>
children — ota-ona (App) yaratgan JSX. Scroll ning state i o'zgarganda children o'sha obyekt bo'lib qoladi va React uni qayta render qilmaydi.
3. React.memo
Yuqoridagilar ishlamasa — keyingi dars.
React Compiler
React jamoasi React Compiler ni chiqardi — build vaqtida komponentlarni avtomatik memoizatsiya qiluvchi vosita. U memo, useMemo, useCallback ni (68-dars, 15–16-darslar) ko'p hollarda keraksiz qiladi. Lekin u ham yuqoridagi qoidalarga asoslanadi: komponentlar sof bo'lishi, state o'zgarmas tarzda yangilanishi kerak. Rendering ni tushunish — kompilyator bilan ham, kompilyatorsiz ham zarur.
Nima uchun shunday?
Nima uchun React ota-ona render bo'lganda barcha bolalarni ham render qiladi — props o'zgarmaganini tekshirsa yaxshiroq emasmi?
Tekshirish ham bepul emas. Har bir komponent uchun barcha props larni oldingi qiymatlar bilan solishtirish — xotira (eski props larni saqlash) va vaqt talab qiladi. Ko'p komponentlar uchun esa qayta render qilish solishtirishdan arzonroq: kichik funksiya, bir necha JSX elementi. Bundan tashqari, props ning o'zi o'zgarmagan bo'lsa ham, komponent Context, tashqi store yoki joriy vaqtni o'qishi mumkin — "props bir xil" har doim ham "natija bir xil" degani emas. Shuning uchun React xavfsiz standartni tanlagan: hammasini render qil, DOM ni esa faqat zarur bo'lganda o'zgartir. Haqiqatan sekin joylarda esa sizga memo bilan "bu yerda solishtir" deyish imkoniyatini beradi.
Xulosa
Eslab qoling:
- Yangilanish: trigger → render (funksiyani chaqirish, Virtual DOM) → commit (DOM ga faqat farqlar)
- Render ≠ DOM o'zgarishi; render arzon, keraksiz DOM o'zgarishlari esa qimmat
- Trigger: o'z state i, ota-ona render i, Context, tashqi store; props o'zgarishi alohida trigger emas
- Ota-ona render bo'lsa — bolalar ham, props o'zgarmagan bo'lsa ham
- Reconciliation: tur o'zgarsa — butunlay qayta yaratish; ro'yxatlarda
key - State daraxtdagi joyda yashaydi;
keyni o'zgartirish — state ni tozalash - Komponentni komponent ichida e'lon qilmang
- Birinchi optimizatsiyalar: state ni pastga tushirish,
childrenorqali uzatish
Keyingi dars
68-dars: React.memo — component ni keshlash, qachon kerak