Mundarija (29)
- Bu darsda
- 1. Nega bu kerak?
- 2. Uch sabab
- 2.1 Bitta misolda uchalasi
- 2.2 «Narx +»: o'z state'i va ota
- 2.3 «Tema»: ota va context
- 3. "Props o'zgardi" mifi
- 3.1 Props o'z-o'zidan o'zgarmaydi
- 3.2 React faqat set ni eshitadi
- 4. "setState doim chizadi" mifi
- 4.1 Bir xil qiymat — bailout
- 4.2 G'alati istisno: "yana bir marta"
- 4.3 Yangi obyekt — doim yangi
- 5. Context: hamma iste'molchi
- 6. "Qayta render — yomon" mifi
- 7. Render sonini qanday o'lchash
- 8. Vazifalar qadami: 18 056 renderni ochamiz (o'lchov, commit yo'q)
- 8.1 Ssenariylar
- 8.2 Katak: 18 056 = zanjir
- 8.3 Qolganlari
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): sababni toping
- 2-mashq (o'rta): mehmonlar hisoblagichi
- 3-mashq (qiyin): context qiymatini barqarorlash
- 4-mashq: "Why did this render?"
- 11. Real ishda
- Xulosa
- Manbalar
Qayta render sabablari va miflar: komponent aynan nega chiziladi
Qisqacha: Komponent faqat uch sababdan qayta chiziladi: (1) o'z state'i o'zgardi (
useState,useReducer, tashqi do'kon), (2) otasi qayta chizildi, (3) o'qiyotgan context qiymati o'zgardi. "Props o'zgardi" — alohida sabab emas: props faqat ota chizilganda keladi, ota chizilsa esa bola props o'zgarmasa ham chiziladi. Bir xil qiymatnisetqilsangiz React chizishni to'xtatadi (Object.is), lekin yangi obyekt — doim "yangi".vazifalardagi bitta katakka 18 056 render — shu uch qoidaning zanjiri: biz uni qatorma-qator ochamiz.
Bu darsda
- Qayta renderning uchta sababini konsol loglari bilan ajrata olasiz.
- "Props o'zgardi", "butun ilova chiziladi", "
setStatedoim chizadi" kabi miflarni o'lchov bilan rad etasiz. - Bir xil qiymatda React qanday to'xtashini (bailout) va uning g'alati istisnosini bilasiz.
- Render sonini to'g'ri o'lchash usullarini tanlaysiz.
vazifalardagi 18 056 render qayerdan kelganini tushuntira olasiz.
Oldin bilishingiz kerak: Render va commit, Reconciliation, Virtual DOM va Fiber, Context II: performance va chegaralar, React DevTools bilan ishlash.
1. Nega bu kerak?
Render va commit darsidagi jadvalda bitta raqam ko'zga tashlandi: 1 000 vazifali ro'yxatda bitta katakni bosish — 18 056 komponent render. Bitta vazifa o'zgardi, 999 tasi o'sha. Nega React ularning hammasini qayta chaqirdi?
Sardor birinchi xayolini aytdi: "Props o'zgargandir-da". Jasur aka so'radi: "Qaysi props? 999 ta qatorning matni ham, holati ham o'sha-ku". Bu savolga javob topish uchun avval qoidani aniq bilish kerak: React komponentni qachon chaqiradi. Taxmin bilan optimallashtirsangiz, memo ni noto'g'ri joyga qo'yasiz va hech narsa tezlashmaydi.
Hayotiy o'xshatish: «Bahor» oshxonasida taom uch holatda qayta tayyorlanadi. Mehmon buyurtmasini o'zgartirdi (o'z state'i). Bosh oshpaz butun stolning buyurtmasini qayta boshladi (ota). Yoki oshxonaning umumiy qoidasi o'zgardi — "bugundan hamma taom achchiqsiz" (context). Boshqa sabab yo'q. "Taomning retsepti o'zgardi" — bu ham faqat shu uchtasidan biri orqali sodir bo'ladi.
2. Uch sabab
2.1 Bitta misolda uchalasi
«Bahor» sahifasida uch qism bor. Menu — narx state'i bilan, Footer — memo bilan o'ralgan, uning ichida esa tema context'ini o'qiydigan ThemeLabel. memo ni useTransition darsida bir gap bilan ko'rgansiz: props o'sha bo'lsa, komponent qayta chizilmaydi. Har komponent chizilganda ismini yozadi:
import { createContext, memo, use, useState } from "react";
const ThemeContext = createContext("yorug'");
function Logo() {
console.log("· Logo");
return <h1>«Bahor»</h1>;
}
function Price({ value }) {
console.log("· Price");
return <p>Osh: {value} so'm</p>;
}
function Menu() {
const [price, setPrice] = useState(35000);
console.log("Menu");
return (
<section>
<Logo />
<Price value={price} />
<button onClick={() => setPrice(price + 1000)}>Narx +</button>
</section>
);
}
function ThemeLabel() {
const theme = use(ThemeContext);
console.log("· ThemeLabel");
return <p>Tema: {theme}</p>;
}
const Footer = memo(function Footer() {
console.log("Footer");
return <ThemeLabel />;
});
function App() {
const [theme, setTheme] = useState("yorug'");
console.log("App");
return (
<ThemeContext value={theme}>
<Menu />
<Footer />
<button onClick={() => setTheme("qorong'i")}>Tema</button>
</ThemeContext>
);
}Konsolni uch bo'lakka bo'lib o'qing: birinchi chizish, «Narx +» va «Tema». Har bo'lakda kim chizilgani — keyingi jadvallarda.
Konsolda:
App
Menu
· Logo
· Price
Footer
· ThemeLabel
Menu
· Logo
· Price
App
Menu
· Logo
· Price
· ThemeLabelEkranda:
«Bahor»
Osh: 36000 so'm
Narx +
Tema: qorong'i
TemaBirinchi olti qator — birinchi chizish. Keyin ikki bosish.
2.2 «Narx +»: o'z state'i va ota
| Kim | Chizildimi | Sabab |
|---|---|---|
App |
yo'q | uning state'i o'zgarmadi |
Menu |
ha | o'z state'i (price) |
Logo |
ha | otasi (Menu) chizildi |
Price |
ha | otasi chizildi |
Footer, ThemeLabel |
yo'q | ular Menu ning ostida emas |
Ikki narsaga e'tibor bering. Logo ga hech qanday props berilmagan — u baribir chizildi. Sababi faqat bitta: Menu qayta chizildi, Menu esa o'z JSX'ida <Logo /> ni qaytaradi. React sukut bo'yicha otasi chizilgan har bolani chizadi.
Ikkinchisi: state Menu da yashaydi va render o'sha joydan pastga ketadi. Yuqoridagi App va yonidagi Footer tegilmadi. "Bitta state o'zgarsa, butun ilova qayta chiziladi" — mif: faqat state egasi va uning ostidagi daraxt.
2.3 «Tema»: ota va context
| Kim | Chizildimi | Sabab |
|---|---|---|
App |
ha | o'z state'i (theme) |
Menu, Logo, Price |
ha | otasi chizildi (zanjir) |
Footer |
yo'q | memo, props yo'q — o'sha |
ThemeLabel |
ha | context (ThemeContext) o'zgardi |
Eng qiziq qator — oxirgisi. Footer chizilmadi, demak "ota chizildi" sababi ThemeLabel ga yetib kelmadi. Lekin ThemeLabel baribir chizildi: u use(ThemeContext) bilan context o'qiydi (use()), context qiymati esa "yorug'" dan "qorong'i" ga o'zgardi. React context'ni o'qiydigan har komponentni topib, uni o'zi chizadi — oradagi memo larni aylanib o'tib.
flowchart TD
A{"Komponent chiziladimi?"} --> B["O'z state'i o'zgardi"]
A --> C["Otasi chizildi"]
A --> D["O'qiyotgan context o'zgardi"]
C --> E{"memo bormi, props o'shami?"}
E -->|"ha"| F["Chizilmaydi"]
E -->|"yo'q"| G["Chiziladi"]
B --> G
D --> GDiagrammaga qarang: memo faqat bitta sababni — "ota chizildi" ni — to'xtata oladi. O'z state'i va context — memo dan o'tadi.
Tekshirib ko'ring: Agar
Footerdanmemoolib tashlansa, «Tema» bosilganda konsolda nima o'zgaradi?
Javob
Footer qatori qo'shiladi (App chizildi → Footer uning bolasi). ThemeLabel ham chiziladi — endi ikki sabab bilan: otasi chizildi va context o'zgardi. React uni baribir bir marta chizadi. Ya'ni bu misolda memo faqat bitta keraksiz renderni (Footer) tejadi.
3. "Props o'zgardi" mifi
3.1 Props o'z-o'zidan o'zgarmaydi
Props — ota renderida yasalgan obyekt. Bola uni "kuzatmaydi", React ham "props o'zgardimi" deb vaqti-vaqti bilan tekshirmaydi. Props'ning yangi qiymati faqat ota chizilganda keladi. Demak, "props o'zgardi, shuning uchun chizildi" aslida "ota chizildi, shuning uchun chizildi (props ham boshqa bo'lib qoldi)".
Teskarisi ham to'g'ri: props o'sha bo'lsa ham, ota chizilsa — bola chiziladi (Logo misoli). Props'ga qaraydigan yagona narsa — memo: u ota renderida bolaning yangi props'ini eskisi bilan solishtiradi va o'sha bo'lsa, renderni to'xtatadi (memo, useMemo, useCallback).
3.2 React faqat set ni eshitadi
Mifning ikkinchi yuzi: "ma'lumot o'zgarsa, React o'zi chizadi". Yo'q — React faqat set…, dispatch va context o'zgarishini biladi:
let guests = 0; // ❌ modul o'zgaruvchisi — React bilmaydi
function App() {
console.log("App chizildi, mehmonlar:", guests);
function handleClick() {
guests += 1;
console.log("guests =", guests);
}
return (
<div>
<p>Bugun mehmonlar: {guests}</p>
<button onClick={handleClick}>Mehmon keldi</button>
</div>
);
}Konsolda:
App chizildi, mehmonlar: 0
guests = 1
guests = 2Ekranda:
Bugun mehmonlar: 0
Mehmon keldiO'zgaruvchi 2 bo'ldi, ekran 0 da qoldi. React uchun hech narsa sodir bo'lmadi — trigger yo'q (Render va commit). Xuddi shu narsa props obyektini, state ichidagi massivni to'g'ridan-to'g'ri o'zgartirganda ham bo'ladi (State III: immutable yangilash).
4. "setState doim chizadi" mifi
4.1 Bir xil qiymat — bailout
set ga hozirgi qiymatning o'zini bersangiz, React chizishni boshlamaydi. Solishtirish — Object.is (Tenglik va Object.is). Bu bailout (chiqib ketish) deyiladi:
import { useState } from "react";
function App() {
const [dish, setDish] = useState("Osh");
console.log("App chizildi:", dish);
return <button onClick={() => setDish("Osh")}>Osh</button>;
}Konsolda:
App chizildi: OshUch bosish — birorta ham render yo'q. React "Osh" ni "Osh" bilan solishtirdi, Object.is — true, ish shu yerda tugadi.
4.2 G'alati istisno: "yana bir marta"
Endi boshqa tartib: avval qiymat o'zgaradi, keyin o'sha yangi qiymat yana ikki marta beriladi:
import { useState } from "react";
function App() {
const [dish, setDish] = useState("Osh");
console.log("App chizildi:", dish);
return <button onClick={() => setDish("Manti")}>Manti</button>;
}Konsolda:
App chizildi: Osh
App chizildi: Manti
App chizildi: MantiIkkinchi bosish ("Manti" → "Manti") bitta ortiqcha render berdi, uchinchisi — yo'q. Bu xato emas, hujjatlangan xulq. React hujjati (useState, "Caveats") shunday deydi: qiymat o'sha bo'lsa, React komponentni va uning bolalarini qayta chizmaydi, lekin ba'zan bolalarga o'tmasdan oldin komponentning o'zini chaqirishi mumkin.
Sababi — Fiber dagi ikki daraxt. Object.is bilan oldindan tekshirish uchun React Fiber'ning ikkala nusxasi (current va alternate) "kutilayotgan ish yo'q" holatida bo'lishini talab qiladi. Birinchi o'zgarishdan keyin nusxalardan birida hali eski belgi qoladi. Shuning uchun React bir marta komponentni chaqiradi, natija o'sha ekanini ko'radi va commit'siz to'xtaydi. Amaliy xulosa bitta: bu render arzon (bolalar chizilmaydi) va unga tayanmang — console.log sonini "aniq hisob" deb ishlatmang.
4.3 Yangi obyekt — doim yangi
Obyekt bilan esa bailout deyarli ishlamaydi:
import { useState } from "react";
function App() {
const [order, setOrder] = useState({ dish: "Osh", qty: 1 });
console.log("App chizildi:", order.dish, order.qty);
return (
<button onClick={() => setOrder({ ...order })}>Saqla</button>
);
}Konsolda:
App chizildi: Osh 1
App chizildi: Osh 1
App chizildi: Osh 1{ ...order } — mazmuni o'sha, lekin yangi obyekt. Object.is(eski, yangi) — false. React mazmunni chuqur solishtirmaydi: bu qimmat bo'lardi va har doim ham to'g'ri emas. Bu mif emas, qoida: React havola (reference) bo'yicha solishtiradi. Qoida memo, useEffect massivi va context qiymatida ham bir xil — keyingi darslarning asosiy mavzusi.
Tekshirib ko'ring:
setItems(items.filter(() => true))— mazmun o'sha. Qayta render bo'ladimi?
Javob
Bo'ladi. filter doim yangi massiv qaytaradi, hatto hech narsa olib tashlanmasa ham. Object.is havolani solishtiradi — false. Chizishni oldini olish kerak bo'lsa, o'zgarish yo'qligini o'zingiz tekshiring va eski massivni qaytaring: setItems((eski) => (yangi.length === eski.length ? eski : yangi)).
5. Context: hamma iste'molchi
Context o'zgarganda React uni o'qiydigan har komponentni chizadi. "O'zgardi" — yana Object.is bo'yicha. Context qiymati obyekt bo'lsa va u har renderda yangidan yasalsa — har renderda "o'zgardi":
import { createContext, memo, use, useState } from "react";
const ThemeContext = createContext(null);
const ThemeButton = memo(function ThemeButton() {
const { setTheme } = use(ThemeContext);
console.log("ThemeButton");
return (
<button onClick={() => setTheme("qorong'i")}>Qorong'i</button>
);
});
function App() {
const [theme, setTheme] = useState("yorug'");
const [count, setCount] = useState(0);
console.log("App", count, theme);
return (
<ThemeContext value={{ theme, setTheme }}>
<ThemeButton />
<button onClick={() => setCount(count + 1)}>Sanagich</button>
</ThemeContext>
);
}Konsolda:
App 0 yorug'
ThemeButton
App 1 yorug'
ThemeButton
App 1 qorong'i
ThemeButton«Sanagich» temaga umuman tegmaydi. ThemeButton — memo da va faqat setTheme ni ishlatadi, u esa doim o'sha funksiya. Lekin baribir chizildi: { theme, setTheme } — har App renderida yangi obyekt, demak context "o'zgardi". Bu Context II darsidagi chegara. Davosi — qiymatni barqaror qilish (useMemo, 3-mashqda) yoki context'ni ikkiga bo'lish.
6. "Qayta render — yomon" mifi
Oxirgi va eng zararli mif. Yuqoridagi misollarda ortiqcha renderlarni topdik — demak, hammasini yo'qotish kerakmi? Yo'q. Render — oddiy JavaScript funksiyasi chaqiruvi. Logo kabi komponent mikrosekundlarda chiziladi, DOM'ga esa natija o'sha bo'lsa umuman tegilmaydi (Render va commit).
vazifalar dagi raqamlar buni yaxshi ko'rsatadi. E'lon o'chganda 17 ta komponent qayta chiziladi — ularning ko'pi "keraksiz". Lekin bu foydalanuvchi sezadigan hech narsa emas: bitta kadrning kichik bo'lagi. Katak bosilganda esa 18 056 render — 1 000 vazifada 48 ms, 10 000 da 264 ms. Farq — soni va narxi, "render bor-yo'qligi" emas.
Shuning uchun tartib doim bir xil:
- Sekinlikni seziladigan joyda o'lchang (INP, Profiler).
- Qaysi komponent ko'p yoki qimmat chizilayotganini toping.
- Uchta sababdan qaysi biri ekanini aniqlang.
- Faqat shundan keyin davolang — avval kompozitsiya, keyin
memo.
Har komponentni oldindan memo ga o'rash — o'zi ham narx: har renderda props solishtiriladi, kod murakkablashadi, yangi obyekt berilsa esa baribir ishlamaydi. Bu "erta optimallashtirish" ning klassik ko'rinishi (memo, useMemo, useCallback).
7. Render sonini qanday o'lchash
| Usul | Nimani sanaydi | E'tibor |
|---|---|---|
console.log render tanasida |
har chaqiruvni | StrictMode'da ikki marta, tashlangan renderlar ham |
useRef hisoblagich useEffect da |
commit'larni | Render va commit dagi 3-mashq |
| DevTools "Highlight updates" | ko'z bilan, tez | aniq son yo'q |
| DevTools Profiler, "Why did this render?" | har commit, har komponent va sabab | yozib olish kerak |
<Profiler onRender> |
daraxt qismi, vaqt bilan | Performance'ni o'lchash |
| DevTools hook'i (kanon skripti) | butun ilova, avtomatik | o'lchov vositalari uchun |
Profiler'da sozlamalardan "Record why each component rendered while profiling" yoqilsa, har komponent uchun "Why did this render?" (nega chizildi?) bo'limi to'ladi (React ilovani debug qilish). Uning javoblari aynan shu darsdagi uchta sabab:
| DevTools yozuvi | Sabab |
|---|---|
| "The parent component rendered." | ota chizildi |
| "• Hook 1 changed" yoki "• Hook changed:" + hooklar ro'yxati | o'z state'i (1-hook) |
| "• Context changed" | context |
"• Props changed:" + props nomi (masalan vazifalar) |
ota chizildi, props boshqa |
Oxirgi qator alohida sabab emas — bu ham "ota chizildi" ning bir ko'rinishi. Matnlar React DevTools manbasidan (react-devtools-shared, WhatChanged.js, react-devtools-core 8.0.0) olindi.
8. Vazifalar qadami: 18 056 renderni ochamiz (o'lchov, commit yo'q)
8.1 Ssenariylar
Kanon o'lchovi (natijalar/18-renderlar-12.txt, holat 12, 1 000 vazifa) — har ssenariyda nechta komponent render:
- katak bosish5 commit18 056 render
- yangi vazifa qo'shish5 commit18 068 render
- qidiruv: bitta harf2 commit6 035 render
- qidiruv: 9 harf10 commit237 render
- e'lon o'chishi1 commit17 render
- tema tanlovi1 commit2 render
Manba: O'lchandi: vazifalar holat 12, olchov/renderlar.mjs (React DevTools hook usuli), Chrome headless, 1 000 vazifa, soxta server, 2026-10-13
Grafikda ikki ustun tepada, qolganlari deyarli ko'rinmaydi. Har birini uchta sabab bilan tushuntiramiz.
8.2 Katak: 18 056 = zanjir
Bosish App dagi vazifalar state'ini o'zgartiradi (optimistik, keyin server tasdig'i — useOptimistic). Keyin zanjir:
App— o'z state'i.vazifalaro'zgardi.VazifaRoyxati— ota. Umemoda (#02), lekin props'ikorinadigan—useMemo([vazifalar, …])natijasi.vazifalaro'zgardi → yangi massiv →memo"props o'zgardi" deydi.- 1 000 ta
VazifaQatori— ota. Ularmemosiz.VazifaRoyxatichizildi → hammasi chizildi. - Har qator ichida 5 komponent — ota.
OddiyQator,Qator,BelgilanganMatnva ikkitaAmalTugmasi.
Bir qatorga 6 komponent × 1 000 qator × 3 commit = 18 000. Qolgan 56 — App, Aloqa, XatoChegarasi, StatistikaPaneli va boshqalar (faylda: AmalTugmasi×6000, VazifaQatori×3000, OddiyQator×3000, Qator×3000, BelgilanganMatn×3000). Nega 5 commit'dan 3 tasi? Faylda App×3 — qolgan ikki commit'da App umuman chizilmagan, ular ro'yxatdan tashqaridagi kichik yangilanishlar edi (StatistikaPaneli×4 shu yerdan).
Endi asosiy savol: VazifaQatori ga memo qo'ysak — yetadimi? Kanon QADAMLAR.md dagi tashxis: yo'q. korinadiganVazifalar() har chaqirilganda vazifalardan yangi Vazifa obyektlarini yasardi (Klasslar). O'zgarmagan 999 vazifa ham yangi obyekt bo'lib kelardi — memo(VazifaQatori) ning Object.is(eski.vazifa, yangi.vazifa) i doim false. «Yangi obyekt — doim yangi» bo'limidagi qoida aynan shu yerda.
8.3 Qolganlari
- Qidiruv, bitta harf ("v") — 6 035. "v" ni hamma vazifa o'z ichiga oladi: har qatorda belgilangan matn (
BelgilanganMatn) haqiqatan o'zgaradi. Bu keraksiz render emas — kerakli ish. Uni kamaytirish emas, to'xtatib bo'ladigan qilish kerak edi (useDeferredValue). - E'lon o'chishi — 17.
Appningelonstate'i o'zgardi →Appva uningmemosiz bolalari (Aloqa, forma, filtrlar,Statistika…). Ro'yxat tegilmadi:VazifaRoyxatining props'i o'sha,memoishladi. - Tema — 2.
TemaProvider(o'z state'i) vaTemaTanlov(context).Appumuman chizilmadi — nega, keyingi darsda (Kompozitsiya orqali optimallashtirish).
Vaqtda (natijalar/20-oldin.txt): katak — 1 000 vazifada mediana 48 ms, 10 000 da 264 ms. Tuzatish — memo, useMemo, useCallback darsida: asl obyektlar + memo(VazifaQatori) = 18 056 → 68.
9. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| props yo'q komponent ham chiziladi | otasi chizildi | kompozitsiya yoki memo |
memo bor, baribir chiziladi |
props'da yangi obyekt/funksiya yoki context | barqaror props, context'ni barqarorlash |
| o'zgaruvchi o'zgardi, ekran eski | React faqat set ni biladi |
state yoki tashqi do'kon (useSyncExternalStore) |
| bir xil qiymatdan keyin bitta ortiqcha log | hujjatlangan bailout istisnosi | e'tibor bermang, natija commit'siz |
setX({...x}) har safar chizadi |
yangi obyekt | o'zgarmagan bo'lsa eskisini qaytaring |
render sonini console.log bilan sanash noto'g'ri |
StrictMode, tashlangan renderlar | Profiler yoki effektdagi hisob |
10. Mashqlar
Mashqlar kurs/mashqlar/18/18-render-sabablari/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): sababni toping
Har holatda komponent nega chizilgan?
Headerhech qanday props olmaydi,Appdagi soat har soniya yangilanadi:CartBadgeuse(CartContext)qiladi, savatga taom qo'shildi:CounterichidasetCount(count + 1):Priceningvalueprops'i o'zgardi:
Yechim
Ota, context, state — va to'rtinchisi ham ota. value faqat ota qayta chizilganda yangi qiymat bilan keladi; ota chizilmasa, props o'zgarishi mumkin emas. "Props o'zgardi" — oqibat, sabab emas.
2-mashq (o'rta): mehmonlar hisoblagichi
«Mehmonlar hisoblagichi» bo'limidagi kod ekranni yangilamaydi. Uni shunday tuzating: har bosishda ekran yangilansin va konsolga App chizildi, mehmonlar: N chiqsin. Ikki bosishdan keyin kutilgan natija:
Konsolda:
App chizildi, mehmonlar: 0
App chizildi, mehmonlar: 1
App chizildi, mehmonlar: 2Yechim
import { useState } from "react";
function App() {
const [guests, setGuests] = useState(0);
console.log("App chizildi, mehmonlar:", guests);
return (
<div>
<p>Bugun mehmonlar: {guests}</p>
<button onClick={() => setGuests(guests + 1)}>
Mehmon keldi
</button>
</div>
);
}Ekranda:
Bugun mehmonlar: 2
Mehmon keldiModul o'zgaruvchisi o'rniga state: setGuests — trigger, React App ni yangi qiymat bilan chizadi. Modul o'zgaruvchisining yana bir yashirin xavfi bor: u komponentning hamma nusxalari uchun bitta. Sahifada ikkita hisoblagich bo'lsa, ular bir-birining sonini o'zgartirardi.
3-mashq (qiyin): context qiymatini barqarorlash
«Context: hamma iste'molchi» bo'limidagi misolni tuzating: «Sanagich» bosilganda ThemeButton chizilmasin, «Qorong'i» bosilganda esa chizilsin (u yerda theme haqiqatan o'zgaradi). Faqat App ni o'zgartiring. Ishora: context qiymati — obyekt; uni faqat theme o'zgarganda yangidan yasang — useMemo (useDeferredValue darsida bir gap bilan ko'rgansiz: massivdagi qiymatlar o'zgarmasa, o'sha natijani qaytaradi).
Yechim
import { createContext, memo, use, useMemo, useState } from "react";
const ThemeContext = createContext(null);
const ThemeButton = memo(function ThemeButton() {
const { setTheme } = use(ThemeContext);
console.log("ThemeButton");
return (
<button onClick={() => setTheme("qorong'i")}>Qorong'i</button>
);
});
function App() {
const [theme, setTheme] = useState("yorug'");
const [count, setCount] = useState(0);
const value = useMemo(() => ({ theme, setTheme }), [theme]);
console.log("App", count, theme);
return (
<ThemeContext value={value}>
<ThemeButton />
<button onClick={() => setCount(count + 1)}>Sanagich</button>
</ThemeContext>
);
}Konsolda:
App 0 yorug'
ThemeButton
App 1 yorug'
App 1 qorong'i
ThemeButton«Sanagich» dan keyin ThemeButton yo'q: value — o'sha obyekt (theme o'zgarmadi), context "o'zgarmadi", memo esa "ota chizildi" ni to'xtatdi. «Qorong'i» da theme o'zgardi — yangi obyekt, ThemeButton chizildi. setTheme ni massivga qo'shish shart emas: React set funksiyasi doim o'sha (State I). Ikkala himoya ham kerak edi: memo siz ThemeButton «Sanagich» da otasi tufayli chizilardi.
4-mashq: "Why did this render?"
vazifalar holat 12 ni 1 000 vazifa bilan oching. React DevTools → Profiler, sozlamalarda "Record why each component rendered while profiling" ni yoqing. Yozib olishni boshlang, bitta katakni bosing, to'xtating. Uchta commit'ni tanlab, VazifaRoyxati va bitta VazifaQatori uchun "Why did this render?" ni o'qing. Javoblar «Katak: 18 056 = zanjir» bo'limidagi qaysi qadamlarga mos?
Yechim
VazifaRoyxati — "• Props changed:" va yonida vazifalar (2-qadam: yangi massiv). VazifaQatori — "The parent component rendered." (3-qadam). App da — "• Hook … changed" (1-qadam: state yoki optimistik qatlam). Flamegraph'da 1 000 ta qator sariq-yashil chiziqlar bilan to'lib ketadi — hammasi ishlagan. Profiler bilan ishlash to'liq — Performance'ni o'lchash darsida.
11. Real ishda
- Kod ko'rigi (code review): "bu
memonimaga kerak?" savoliga javob — qaysi sababni to'xtatyapti. Agar komponent o'z state'i yoki context tufayli chizilsa,memofoydasiz. - Global state kutubxonalari: Zustand, Redux kabi kutubxonalar context'ning "hamma iste'molchi" muammosini selektorlar bilan hal qiladi — faqat kerakli bo'lak o'zgarsa chizadi (keyingi qismlarda).
- Profiling madaniyati: katta jamoalarda "sekin" degan PR'ga Profiler skrinshoti va "Why did this render?" sabablari qo'shiladi.
- Intervyu savollari: "Komponent qachon qayta render bo'ladi?", "Props o'zgarishi renderga sababmi?", "Nega
setStatebilan bir xil obyekt bersam ham chiziladi?", "Context nega hamma iste'molchini chizadi?".
Xulosa
- Uch sabab: o'z state'i, ota render, o'qiyotgan context. Boshqa sabab yo'q.
- "Props o'zgardi" — ota renderining oqibati; ota chizilsa, bola props'i o'sha bo'lsa ham chiziladi (
memosiz). - Render state egasidan pastga ketadi — butun ilova emas.
Object.is: bir xil primitiv — bailout (ba'zan bitta arzon ortiqcha chaqiruv); yangi obyekt — doim "yangi".- Context o'zgarsa, har iste'molchi
memodan o'tib chiziladi; obyekt qiymat har renderda yangi bo'lsa — har renderda. vazifalar: 18 056 =Appstate → yangi massiv →memosiz 1 000 qator × 6 × 3 commit;memo(VazifaQatori)yangiVazifaobyektlari tufayli yetmasdi.
Keyingi dars: Kompozitsiya orqali optimallashtirish — memo dan oldin: state'ni pastga tushirish va children orqali uzatish renderlarni bepul kamaytiradi.
Manbalar
- React:
useState— Caveats (bir xil qiymat va bailout) — react.dev/reference/react/useState - React: "Render and Commit" — react.dev/learn/render-and-commit
- React:
memo— react.dev/reference/react/memo - Kanon:
sinov/18/QADAMLAR.md(#16–#18),natijalar/18-renderlar-12.txt,natijalar/20-oldin.txt
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!