Mundarija (31)
- Bu darsda
- 1. Nega bu kerak?
- 2. Kompilyator nima qiladi
- 2.1 Haqiqiy chiqish
- 2.2 Chiqishni o'qiymiz
- 2.3 Natija oynasida nega yo'q
- 3. Loyihaga ulash
- 3.1 Vite
- 3.2 Bosqichma-bosqich
- 4. Rules of React
- 4.1 Kompilyator nimaga tayanadi
- 4.2 Ko'radi: ref render paytida
- 4.3 Ko'rmaydi: props'ni o'zgartirish
- 4.4 ESLint qoidalari
- 5. Kompilyator nimani qilmaydi
- 5.1 return massiv.map(…) — komponent emas?
- 5.2 Kompilyatsiya qilinsa ham — ro'yxat
- 6. Vazifalar qadami: uch variant o'lchandi (kanonga kirmadi)
- 6.1 Variantlar
- 6.2 Raqamlar
- 6.3 O'qiymiz
- 6.4 Qaror
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): kompilyator nima qiladi?
- 2-mashq (o'rta): keshga chidamli savat
- 3-mashq (qiyin): toza talon
- 4-mashq: vazifalar da kompilyatorni sinab ko'ring
- 9. Real ishda
- Xulosa
- Manbalar
React Compiler: avtomatik memoizatsiya — va nega biz uni o'lchab, qo'shmadik
Qisqacha: React Compiler (1.0, 2025-10-07) — build paytida ishlaydigan Babel plagini: komponentlaringizni o'qib,
useMemo,useCallbackvamemoning ishini avtomatik qo'shadi (har JSX bo'lagi uchun kesh). Vite'da:react()+babel({ presets: [reactCompilerPreset()] }). U faqat Rules of React (toza render, props va state'ni o'zgartirmaslik) bajarilgan kodda to'g'ri ishlaydi; qoida buzilsa — komponentni o'tkazib yuboradi yoki yashirin xato beradi. Biz univazifalarda o'lchadik: katak 32 → 24 ms, lekin har yuklashda +6.6 KB gzip, build ×1.7 vatscturlar xatosi. Ikkala variant ham "yaxshi" INP — kanonga kirmadi.
Bu darsda
- Kompilyator kodingizni nimaga aylantirishini haqiqiy chiqishda o'qiysiz.
- Uni Vite loyihasiga qanday ulash va bosqichma-bosqich joriy etishni bilasiz.
"use no memo", ESLint'ning kompilyator qoidalari va Rules of React'ni tushunasiz.- Kompilyator nimani qilmasligini o'lchov bilan ko'rasiz.
vazifalardagi uch variant (qo'lda, kompilyator + qo'lda, faqat kompilyator) raqamlarini o'qib, qaror chiqarasiz.
Oldin bilishingiz kerak: memo, useMemo, useCallback, Transpilyatsiya: Babel, SWC, esbuild va Oxc, Pure komponentlar va render qoidasi, Vite plaginlari.
1. Nega bu kerak?
memo, useMemo, useCallback darsida vazifalar dagi 18 056 renderni 68 ga tushirdik. Buning uchun to'rt fayl o'zgardi, yangi test yozildi va bir necha soat tahlil qilindi: qaysi props yangi, qaysi obyekt nusxa, qayerda useMemo kerak. Har yangi komponentda bu savollar qaytadan tug'iladi. Bitta unutilgan inline obyekt — va memo jim foydasiz bo'ladi.
React jamoasi 2021 yildan buni avtomatlashtirish ustida ishladi va 2025-10-07 da React Compiler 1.0 ni barqaror deb e'lon qildi (react.dev blog, "React Compiler v1.0"). G'oya: dasturchi oddiy kod yozadi, build vaqtida kompilyator uni o'qib, kerakli joylarga kesh qo'yadi.
Sardor xursand: "Demak, endi memo ni o'rganish shart emasmi?" Jasur aka boshqacha so'radi: "Bizning ilovada qancha foyda beradi va qanchaga tushadi?" Bu dars ikkinchi savolga javob beradi — o'lchov bilan. Natija sizni hayratlantirishi mumkin.
2. Kompilyator nima qiladi
2.1 Haqiqiy chiqish
Kompilyator — npm paketi babel-plugin-react-compiler. Biz uni vaqtinchalik papkada @babel/core 7.29.7 bilan ishga tushirdik. Kirish — oddiy komponent:
export function MenuCard({ dish, price }) {
const label = `${dish} — ${price} so'm`;
return (
<li>
<span>{label}</span>
<button onClick={() => console.log(dish)}>Buyurtma</button>
</li>
);
}Chiqish (babel-plugin-react-compiler 1.0.0, target: "19", JSX saqlangan). Uzun ko'rinadi, lekin bitta naqsh takrorlanadi: if ($[n] !== …) — "o'zgardimi?", else — "keshdan ol". Shu naqshni toping:
import { c as _c } from "react/compiler-runtime";
export function MenuCard(t0) {
const $ = _c(7);
const {
dish,
price
} = t0;
const label = `${dish} — ${price} so'm`;
let t1;
if ($[0] !== label) {
t1 = <span>{label}</span>;
$[0] = label;
$[1] = t1;
} else {
t1 = $[1];
}
let t2;
if ($[2] !== dish) {
t2 = <button onClick={() => console.log(dish)}>Buyurtma</button>;
$[2] = dish;
$[3] = t2;
} else {
t2 = $[3];
}
let t3;
if ($[4] !== t1 || $[5] !== t2) {
t3 = <li>{t1}{t2}</li>;
$[4] = t1;
$[5] = t2;
$[6] = t3;
} else {
t3 = $[6];
}
return t3;
}Kompilyator chiqishi uzun qatorli — u telefon uchun formatlanmagan, o'qishga yetarli.
2.2 Chiqishni o'qiymiz
const $ = _c(7);— komponent uchun 7 katakli kesh massivi. U har komponent nusxasida bitta, renderlar orasida saqlanadi (ichkarida — hook, React 19 ning o'zida:react/compiler-runtime).- Har JSX bo'lagi alohida tekshiriladi:
$[0] !== label— "oldingilabelbilan bir xilmi?" Bir xil bo'lsa — eski element ($[1]), aks holda yangisi yasaladi va keshga yoziladi. - Tugmadagi inline funksiya
() => console.log(dish)— endidisho'zgarmasa o'sha funksiya va o'sha element. Bu — siz qo'ldauseCallbackbilan qiladigan ish. - Oxirgi
<li>— ikki bolasi o'zgarmasa, o'sha element. Kompozitsiya darsida ko'rgandek: o'sha element — React bu qismni qayta chizmaydi.
Ya'ni kompilyator memo() o'ramini qo'shmaydi. U komponent ichida har qiymat va har JSX elementini o'z bog'liqliklari bilan keshlaydi — useMemo ga o'xshab, lekin useMemo dan nozikroq: shart ichida ham, erta return dan keyin ham. Bog'liqliklar massivini siz emas, kompilyator yozadi — exhaustive-deps xatosi bo'lmaydi.
2.3 Natija oynasida nega yo'q
Saytdagi «Ishga tushir» kodni brauzerda sucrase bilan o'giradi — React Compiler u yerda yo'q (Babel plagini, build vositasi). Shuning uchun bu darsdagi kompilyator chiqishlari — haqiqiy build'dan olingan matn, natija oynasidagi bloklar esa kompilyator nima qilishini qo'lda yozilgan ekvivalent bilan ko'rsatadi.
3. Loyihaga ulash
3.1 Vite
@vitejs/plugin-react 6.1.2 README'sidagi Babel yo'li (kanon o'lchovida aynan shu ishlatildi):
npm install -D @rolldown/plugin-babel @babel/core \
babel-plugin-react-compiler// vite.config.js
import { defineConfig } from "vite";
import react, { reactCompilerPreset } from "@vitejs/plugin-react";
import babel from "@rolldown/plugin-babel";
export default defineConfig({
plugins: [react(), babel({ presets: [reactCompilerPreset()] })],
});Uch yangi devDependency: Babel o'zi, uni Vite 8 (Rolldown, Vite II: vite.config) ga ulaydigan plagin va kompilyator. Vite odatda Babel'siz ishlaydi — kompilyator uni build zanjiriga qaytaradi. Shu README'da yana bir yo'l bor — react({ compiler: true }), kompilyatorning Rust'dagi porti (oxc-transform-react). Lekin README uni "experimental" (sinov bosqichida) deb belgilaydi — production loyihaga hali emas.
Next.js'da kompilyator next.config dagi bitta sozlama bilan yoqiladi (reactCompiler: true) — Next.js'ni keyingi qismlarda o'rganamiz.
3.2 Bosqichma-bosqich
Katta loyihaga birdaniga yoqish xavfli: kompilyator har komponentni o'zgartiradi. React hujjati ("Incremental Adoption") va README ikki vosita beradi:
compilationMode: "annotation"— kompilyator faqat"use memo"direktivasi yozilgan komponentlarni o'zgartiradi. Bittalab yoqasiz, har birini sinaysiz."use no memo"— teskarisi: shu komponentni o'tkazib yubor. Muammo topilganda vaqtinchalik "o'chirgich".
"use no memo" ni sinadik — kompilyator logger'i (logEvent) shunday yozdi:
CompileSkipKomponent kodi kompilyatsiyadan keyin ham aynan o'zgarishsiz qoldi. Direktiva — oddiy satr ifodasi, funksiya tanasining birinchi qatori (Strict mode dagi "use strict" kabi).
React DevTools'da kompilyator ishlagan komponent yonida belgisi chiqadi (React DevTools darsida aytilgan) — qaysi komponent kompilyatsiya qilingani shu yerdan ko'rinadi.
4. Rules of React
4.1 Kompilyator nimaga tayanadi
Kompilyator kodni ishga tushirmaydi — faqat o'qiydi. Kesh to'g'ri bo'lishi uchun u bir nechta narsani taxmin qiladi. Bu taxminlar React hujjatida Rules of React deyiladi (Pure komponentlar va Hooklar qoidalari darslarida bo'laklab o'rgangansiz):
| Qoida | Kompilyator taxmini |
|---|---|
| Render toza | bir xil kirish → bir xil natija, keshni ishlatsa bo'ladi |
| Props va state o'zgartirilmaydi | havola o'sha → mazmun ham o'sha |
| Ref render paytida o'qilmaydi | ref.current renderga ta'sir qilmaydi |
| Hooklar shartsiz chaqiriladi | tartib doim bir xil |
Qoida buzilganini kompilyator ba'zan ko'radi va komponentni o'tkazib yuboradi. Ba'zan esa ko'rmaydi — va kesh noto'g'ri natija beradi.
4.2 Ko'radi: ref render paytida
export function Timer() {
const renders = useRef(0);
renders.current += 1;
return <p>{renders.current}</p>;
}Logger:
CompileError: Cannot access refs during render"Render paytida ref'ga murojaat qilib bo'lmaydi." Kompilyator bu komponentni o'zgartirmadi — kod kirishdagidek qoldi, ilova ishlayveradi, faqat bu komponent tezlashmaydi. vazifalar da kanon shu xatoga duch kelgan edi (Virtualizatsiya darsidagi useOynaVirtual).
4.3 Ko'rmaydi: props'ni o'zgartirish
export function OrderList({ orders }) {
orders.sort((a, b) => a.price - b.price); // ❌ props o'zgardi
return <ul>{orders.map((o) => <li key={o.id}>{o.dish}</li>)}</ul>;
}Logger: CompileSuccess OrderList. Kompilyator orders.sort ni props mutatsiyasi deb bilmadi va ro'yxatni $[0] !== orders sharti bilan keshladi. Bu nimaga olib kelishini natija oynasida ko'ramiz. Kompilyator qo'ygan keshni qo'lda useMemo bilan yozamiz — xulq bir xil:
import { useMemo, useState } from "react";
function OrderList({ orders }) {
// kompilyator shunday kesh qo'yadi:
// orders o'sha bo'lsa — eski natija
const items = useMemo(
() => orders.map((o) => <li key={o}>{o}</li>),
[orders],
);
return <ul>{items}</ul>;
}
function App() {
const [orders] = useState(["Osh", "Manti"]);
const [version, setVersion] = useState(0);
function addLagmon() {
orders.push("Lag'mon"); // ❌ state massivini o'zgartirish
setVersion(version + 1);
}
return (
<div>
<button onClick={addLagmon}>Lag'mon qo'sh</button>
<p>Jami: {orders.length}</p>
<OrderList orders={orders} />
</div>
);
}Ekranda:
Lag'mon qo'sh
Jami: 3
Osh
Manti"Jami: 3", lekin ro'yxatda ikkita taom. orders.push massivni joyida o'zgartirdi — havola o'sha. Kesh "o'zgarmadi" deb eski ro'yxatni berdi. Kompilyatorsiz (keshsiz) bu kod tasodifan to'g'ri ishlardi: App qayta chizilgach, OrderList ham qayta hisoblanardi. Kompilyator yoqilgan kun esa xato paydo bo'ladi — va hech qanday xabar yo'q.
Bu "kompilyator xatosi" emas — kod avvaldan noto'g'ri edi (State III: immutable yangilash). Kompilyator uni yashirin xatodan ko'rinadigan xatoga aylantirdi.
Tekshirib ko'ring:
addLagmonni qanday yozsangiz, ro'yxat kesh bilan ham to'g'ri yangilanadi?
Javob
Massivni o'zgartirmasdan, yangisini yasab: setOrders([...orders, "Lag'mon"]) (useState dan setOrders ni ham olish kerak). Yangi massiv — yangi havola, $[0] !== orders — true, kesh yangilanadi. version state'i ham kerak bo'lmay qoladi. Qoidaga rioya qilgan kod kompilyator bilan ham, usiz ham bir xil ishlaydi — 2-mashqda yozasiz.
4.4 ESLint qoidalari
Qoidalarni build'dan oldin topish uchun eslint-plugin-react-hooks ning 6-versiyasidan boshlab recommended to'plamiga kompilyatorning tahlil qoidalari qo'shilgan. vazifalar da 7.1.1 versiyasi 17-qismdan beri yoqilgan (ESLint II). Biz uni o'sha kodlarda ishga tushirdik (ESLint 10.12.0):
10:3 error Error: Cannot access refs during render
…
8 | export function Timer() {
9 | const renders = useRef(0);
> 10 | renders.current += 1;
| ^^^^^^^^^^^^^^^ Cannot access ref value during render
… react-hooks/refsVa komponent ichida e'lon qilingan komponent (Reconciliation):
6:15 error Error: Cannot create components during render
… react-hooks/static-componentsMath.random() render ichida:
2:29 error Error: Cannot call impure function during render
… react-hooks/purityChiqishlar qisqartirildi (… — tushuntirish matni va kod parchalari). Qoidalar nomi — react-hooks/refs, react-hooks/static-components, react-hooks/purity; yana immutability, set-state-in-render va boshqalar bor. Muhim: orders.sort (props mutatsiyasi) — lint ham, kompilyator ham ushlamadi. Qoidalar ko'p narsani topadi, lekin hammasini emas.
Bu yerda muhim qaror: lint qoidalari kompilyatorsiz ham foydali. Ular vazifalar da lazy ni har urinishda yangidan yasash (lazy) va ref'ni renderda o'qish (holat 23) xatolarini topdi — kompilyator hech qachon yoqilmagan bo'lsa ham.
5. Kompilyator nimani qilmaydi
5.1 return massiv.map(…) — komponent emas?
vazifalar dagi VazifaRoyxati (holat 20) shunday yozilgan:
return vazifalar.map((vazifa) => (
<VazifaQatori
key={vazifa.id}
vazifa={vazifa}
sorov={sorov}
tahrirda={vazifa.id === tahrirId}
/>
));Xuddi shu shakldagi kichik komponentni kompilyatorga berdik:
export function TaskList({ tasks, query }) {
return tasks.map((task) => (
<TaskRow key={task.id} task={task} query={query} />
));
}
function TaskRow({ task }) {
return <li>{task.text}</li>;
}Logger'da nechta komponent nomi chiqishiga qarang (xom chiqish — natijalar/21-compiler-map.txt):
CompileSuccess TaskRowTaskList — logger'da umuman yo'q. Kompilyator sukut bo'yicha (compilationMode: "infer") funksiyani komponent deb taxmin qiladi: nomi katta harf bilan boshlanadi va tanasida JSX yoki hook bor. Bu yerda JSX faqat ichki map callback'ida — kompilyator TaskList ni komponent deb tanimadi va jim o'tkazib yubordi. return <>{tasks.map(…)}</> deb Fragment'ga o'rasak — CompileSuccess TaskList.
| Kod | Logger | TaskList keshlandimi |
|---|---|---|
return tasks.map(…) |
faqat CompileSuccess TaskRow |
yo'q — o'zgarishsiz qoldi |
return <>{tasks.map(…)}</> |
CompileSuccess TaskList, CompileSuccess TaskRow |
ha — _c(…) kesh qo'shildi |
Nima bo'ldi? Kompilyator xato ham, ogohlantirish ham bermadi — shunchaki komponentni ko'rmadi. Shuning uchun bunday "jim o'tkazib yuborish" ni faqat logger yoki DevTools'dagi belgisi orqali bilasiz.
5.2 Kompilyatsiya qilinsa ham — ro'yxat
Fragment bilan kompilyatsiya qilingan TaskList ning chiqishi:
let t1;
if ($[0] !== query || $[1] !== tasks) {
…
t1 = tasks.map(t2);
$[0] = query;
$[1] = tasks;
$[2] = t1;
} else {
t1 = $[2];
}Butun map natijasi — bitta kesh katagi, kaliti — tasks massivi. Bitta vazifa o'zgarsa, massiv yangi — map qaytadan, 1 000 ta yangi element, 1 000 ta TaskRow chaqiruvi. Kompilyator har element uchun alohida memo qo'ymaydi. Shuning uchun ro'yxatlarda «o'sha obyektlar + memo(Qator)» qoidasi kompilyator bilan ham o'z kuchida.
Tekshirib ko'ring: Kompilyatsiya qilingan
TaskRowichidagi<li>kesh bilan saqlanadi. Ro'yxat qayta hisoblangandaTaskRowfunksiyasi baribir chaqiriladimi?
Javob
Ha. map yangi <TaskRow … /> elementlarini yasadi — yangi props obyektlari. React har birini chaqiradi (render soni o'sadi). Lekin TaskRow ichida task.text o'zgarmagan bo'lsa, kesh o'sha <li> elementini qaytaradi va undan pastga ish ketmaydi. Ya'ni render arzonlashadi, lekin yo'qolmaydi — vazifalar dagi C variantida aynan shu ko'rindi.
6. Vazifalar qadami: uch variant o'lchandi (kanonga kirmadi)
6.1 Variantlar
Kanonda #21 — kod qadami emas, o'lchov (QADAMLAR.md). Holat 20 ustiga kompilyator o'rnatildi (babel-plugin-react-compiler 1.0.0, @rolldown/plugin-babel 0.2.4, @babel/core 7.29.7, keyin 8.0.7), uch variant bir xil skriptlar bilan o'lchandi (natijalar/21-kompilyator.txt, Chrome 155, 1 000 va 10 000 vazifa):
| Variant | Nima |
|---|---|
| A | holat 20: qo'lda memo, useMemo (kompilyatorsiz) |
| B | kompilyator + qo'lda memo/useMemo qoldi |
| C | faqat kompilyator: qo'lda memo/useMemo olib tashlandi (natijalar/21-c-src/) |
O'rnatishda npm audit — 0, install skriptli paket yo'q (npm query) — Supply chain tekshiruvi.
6.2 Raqamlar
| A | B | C | |
|---|---|---|---|
| JS+CSS gzip | 85 959 B | 92 525 B | 92 440 B |
| katak 1 000 (mediana) | 32 ms | 24 ms | 32 ms |
| katak 10 000 (mediana) | 120 ms | 104 ms | 120 ms |
| qidiruv 10 000 (eng uzun) | 200 ms | 208 ms | 176 ms |
- A qo'lda — 1 00032 ms
- B kompilyator + qo'lda — 1 00024 ms
- C faqat kompilyator — 1 00032 ms
- A qo'lda — 10 000120 ms
- B kompilyator + qo'lda — 10 000104 ms
- C faqat kompilyator — 10 000120 ms
Manba: O'lchandi: vazifalar holat 20 + babel-plugin-react-compiler 1.0.0, olchov/katak-tezligi.mjs (Event Timing), Chrome 155.0.8059.40 headless, 2026-10-13 (natijalar/21-kompilyator.txt)
Komponent renderlari (1 000 vazifa, olchov/renderlar.mjs):
| Ssenariy | A | B | C |
|---|---|---|---|
| katak | 68 | 31 | 3 029 |
| qidiruv "vazifa 12" | 927 | 76 | 87 |
| e'lon o'chishi | 17 | 2 | 4 |
6.3 O'qiymiz
- B — eng tez. Kompilyator qo'lda qolgan joylarni ham to'ldirdi: e'lon o'chganda 17 render → 2 (
Appningmemosiz bolalari endi keshdan). Katak 1 000 da 32 → 24 ms, 10 000 da 120 → 104 ms. - C — A bilan teng tezlikda, lekin katakda 3 029 render (
VazifaQatori×3000). Bu «Kompilyator nimani qilmaydi» bo'limining o'zi:VazifaRoyxati(return vazifalar.map(…)) kompilyator uchun komponent bo'lmadi,VazifaQatoriga esamemo()qo'shilmaydi. Har qator chaqirildi, lekin uning ichi keshdan qaytdi (OddiyQator×2) — shuning uchun vaqt A dan yomonlashmadi. - Hajm: +6 566 B gzip (+7.6%) — B ham, C ham. Kesh kodi (
$[n] !== …shartlari) har komponentga qo'shiladi va bu har foydalanuvchining har yuklashida keladi. - Qidiruv — uch variantda 176–208 ms: shovqin ichida (useTransition dagi besh o'lchov oralig'ini eslang).
Yana uchta narx — raqamdan tashqarida:
- Build ×1.7: 1 845 / 1 681 / 1 753 ms → 3 115 / 3 049 / 2 960 ms (uch marta).
tsc -byiqildi — kutubxona turlarida. Babel 7 bilan:@rolldown/plugin-babelturlari@types/babel__coredanInputOptionsni topmadi — va bu turni loyihadan tashqaridagiD:/Ilmhamroh/node_modulesdan olgan edi. Kompilyatorning.d.tsiPerformanceMeasureni so'radi,tsconfig.node.jsonda esa DOM lib yo'q. Babel 8 bilan — boshqa ikki xato. Ishlatish uchunskipLibCheck: truekerak bo'lardi — ya'ni kutubxona turlarini tekshirmaslik (tsconfig frontend loyihada).- Uch yangi devDependency — har biri yangilanishi, peer'i va xavfsizlik tekshiruvi bilan.
6.4 Qaror
Kanon qarori (QADAMLAR.md, asosiy qaror 5; hisobot/18-qarorlar.md, qaror 1): kompilyator kanonga kirmadi, package.json va lock holat 20 ga qaytarildi, savol TEXNIK-QARZ 43 ga yozildi.
Mantiq — Paket tanlash va baholash darsidagi kabi: foyda va narxni bir tarozida tortish. Foyda — katak 8–16 ms tezroq, lekin A ham (32 / 120 ms) INP chegarasi 200 ms dan ancha past — ikkalasi ham "yaxshi". Narx — har yuklashda 6.6 KB (sekin 3G'da sezilarli), ikki barobar sekin build va turlar tekshiruvini o'chirish. Qo'lda yozilgan memo lar esa allaqachon bor va test bilan himoyalangan.
Bu qaror abadiy emas. Kompilyator yangi loyihada (qo'lda memo hali yo'q) yoki Rust porti barqaror bo'lganda (build narxi yo'qoladi) boshqacha tarozida bo'ladi. Asosiysi — qaror "hamma ishlatyapti" emas, o'z ilovangizdagi raqamlar bilan qilindi.
7. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| kompilyatordan keyin ro'yxat yangilanmaydi | props yoki state o'zgartirilgan (mutatsiya) | yangi massiv/obyekt yasang |
| DevTools'da yo'q | qoida buzilgan (CompileError) yoki komponent deb tanilmadi |
ESLint xatolarini tuzating; JSX'ni tanaga qaytaring |
Cannot access refs during render |
ref.current render paytida |
state yoki effekt |
Cannot create components during render |
komponent ichida komponent | modul darajasiga chiqaring |
tsc kutubxona turlarida yiqildi |
Babel/plagin turlari | @types/babel__core yoki skipLibCheck (ongli qaror) |
"kompilyator bor, memo kerak emas" — ro'yxat sekin |
elementlar uchun alohida memo yo'q |
o'sha obyektlar + memo(Qator) |
8. Mashqlar
Mashqlar kurs/mashqlar/18/21-kompilyator/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): kompilyator nima qiladi?
Har komponent uchun: kompilyatsiya qilinadimi?
function Price({ value }) { return <b>{value}</b>; }:function Badge() { "use no memo"; return <i>yangi</i>; }:function Count() { const r = useRef(0); r.current++; return <p>{r.current}</p>; }:function list(items) { return <ul /> }(kichik harf bilan):
Yechim
Birinchisi — oddiy toza komponent, CompileSuccess. Ikkinchisi — direktiva bilan o'tkazib yuborildi (CompileSkip). Uchinchisi — ref render paytida, CompileError, kod o'zgarishsiz qoladi. To'rtinchisi — nomi kichik harf bilan: kompilyator uni komponent deb taxmin qilmaydi (React ham JSX'da <list /> ni HTML teg deb o'qirdi — Komponentlar).
2-mashq (o'rta): keshga chidamli savat
«Ko'rmaydi: props'ni o'zgartirish» bo'limidagi kodni tuzating: useMemo (kompilyator keshi) joyida qolsin, lekin «Lag'mon qo'sh» dan keyin ro'yxatda uchta taom bo'lsin. version state'i kerak bo'lmasin.
Ekranda (kutilgan):
Lag'mon qo'sh
Jami: 3
Osh
Manti
Lag'monYechim
import { useMemo, useState } from "react";
function OrderList({ orders }) {
// kompilyator shunday kesh qo'yadi:
// orders o'sha bo'lsa — eski natija
const items = useMemo(
() => orders.map((o) => <li key={o}>{o}</li>),
[orders],
);
return <ul>{items}</ul>;
}
function App() {
const [orders, setOrders] = useState(["Osh", "Manti"]);
function addLagmon() {
setOrders([...orders, "Lag'mon"]); // ✅ yangi massiv
}
return (
<div>
<button onClick={addLagmon}>Lag'mon qo'sh</button>
<p>Jami: {orders.length}</p>
<OrderList orders={orders} />
</div>
);
}Ekranda:
Lag'mon qo'sh
Jami: 3
Osh
Manti
Lag'monYangi massiv — yangi havola, kesh kaliti o'zgardi. version ham kerak emas: setOrders o'zi trigger. Kod kompilyator bilan ham, usiz ham bir xil ishlaydi — bu Rules of React'ning ma'nosi.
3-mashq (qiyin): toza talon
OrderTicket har render'da yangi talon raqamini chiqaradi (Math.random() render ichida) — ESLint react-hooks/purity xatosi. Talon komponent birinchi chizilganda bir marta tanlansin va qayta renderlarda o'zgarmasin. Tekshirish uchun har commit'dan keyin ko'rilgan raqamlarni Set ga yig'ib, uning hajmini konsolga yozing («Yangila» ni ikki marta bosgandan keyin ham 1).
import { useState } from "react";
function OrderTicket({ dish }) {
const ticket = Math.floor(Math.random() * 1000); // ❌ toza emas
return <p>{dish}: talon №{ticket}</p>;
}
function App() {
const [n, setN] = useState(0);
return (
<div>
<button onClick={() => setN(n + 1)}>Yangila</button>
<OrderTicket dish="Osh" />
</div>
);
}Yechim
import { useEffect, useState } from "react";
const seen = new Set();
function OrderTicket({ dish }) {
const [ticket] = useState(() => Math.floor(Math.random() * 1000));
useEffect(() => {
seen.add(ticket);
console.log("har xil talonlar:", seen.size);
});
return (
<p>
{dish}: talon №{ticket}
</p>
);
}
function App() {
const [n, setN] = useState(0);
return (
<div>
<button onClick={() => setN(n + 1)}>Yangila</button>
<OrderTicket dish="Osh" />
</div>
);
}Konsolda:
har xil talonlar: 1
har xil talonlar: 1
har xil talonlar: 1useState(() => …) — boshlang'ich qiymat funksiyasi faqat birinchi renderda chaqiriladi (State I), keyin React saqlangan qiymatni beradi. Bu shaklni ESLint ham, kompilyator ham qabul qiladi (biz ikkalasida sinadik: lint — 0 xato, logger — CompileSuccess OrderTicket). Agar Math.random() render tanasida qolsa, kompilyator natijani keshlab, talonni "tasodifan" muzlatib qo'yishi ham, qo'ymasligi ham mumkin — ya'ni xulq kompilyatorga bog'liq bo'lib qolardi.
4-mashq: vazifalar da kompilyatorni sinab ko'ring
vazifalar ning vaqtinchalik nusxasida (alohida branch, keyin o'chiring) «Vite» bo'limidagi uch paketni --save-exact bilan o'rnating va vite.config.ts ga babel({ presets: [reactCompilerPreset()] }) ni qo'shing. npm run build — hajm qancha o'zgardi? npm run tip — nima bo'ldi? React DevTools'da qaysi komponentlarda bor, qaysilarida yo'q? Commit qilmang.
Yechim
Kutiladigan natija — kanondagi o'lchov: JS+CSS gzip ~6.5 KB ga oshadi, build ikki barobarga yaqin sekinlashadi. Keyin tsc -b tsconfig.node.json da kutubxona turlari xatosi bilan yiqiladi (aniq matn Babel versiyasiga va kompyuteringizdagi node_modules larga bog'liq). — ko'p komponentlarda bor, lekin VazifaRoyxati da yo'q (return vazifalar.map(…)), useOynaVirtual ishlatadigan qismlarda ham tekshiring. Xulosa o'zingizniki — lekin u raqamlarga tayansin, «Qaror» bo'limidagi kabi.
9. Real ishda
- Yangi loyihalar: 2026 yil holatiga ko'p shablonlar (Next.js, Expo) kompilyatorni taklif qiladi yoki sukut bo'yicha yoqadi. Qo'lda
memoyozish kamayadi — lekin uni o'qish va kompilyator qachon ishlamasligini bilish qoladi. - Mavjud loyihalar: avval
eslint-plugin-react-hooksning kompilyator qoidalari yoqiladi va xatolar tuzatiladi, keyincompilationMode: "annotation"bilan bittalab. - Kod ko'rigi: "bu yerda
useMemokerakmi?" bahslari kamayadi; o'rniga "bu kod Rules of React'ga mosmi?" savoli muhimroq bo'ladi. - Intervyu savollari: "React Compiler nima qiladi?", "Kompilyator bor bo'lsa,
memokerakmi?", "Rules of React nima va nega kompilyator ularga tayanadi?", "Kompilyatorni qanday bosqichma-bosqich joriy etasiz?".
Xulosa
- React Compiler 1.0 — build vaqtidagi Babel plagini: har qiymat va JSX bo'lagini bog'liqliklari bilan keshlaydi (
_c(n)massivi),useMemo/useCallbackni avtomatik qiladi. - Vite:
react()+babel({ presets: [reactCompilerPreset()] }); bosqichma-bosqich —compilationMode: "annotation"va"use no memo". - Rules of React shart: ref render paytida, toza bo'lmagan funksiya — kompilyator o'tkazib yuboradi; props mutatsiyasini ko'rmaydi va kesh yashirin xato beradi.
- Kompilyator
memo()qo'shmaydi vareturn massiv.map(…)qaytaradigan funksiyani komponent deb tanimasligi mumkin — ro'yxatlarda qo'ldamemo+ o'sha obyektlar kerak. vazifalar: B (kompilyator + qo'lda) katak 32 → 24 ms, lekin +6.6 KB gzip, build ×1.7,skipLibCheckkerak; INP har ikkalasida "yaxshi" — kanonga kirmadi.
Keyingi dars: Performance'ni o'lchash: Profiler va Performance Tracks — React DevTools Profiler, <Profiler> API va Chrome'dagi React treklari bilan o'lchovni o'zingiz qilasiz.
Manbalar
- React Compiler v1.0 e'loni (2025-10-07) — react.dev/blog/2025/10/07/react-compiler-1
- React: "React Compiler" — react.dev/learn/react-compiler
- React: "Rules of React" — react.dev/reference/rules
@vitejs/plugin-react6.1.2 README — "React Compiler" bo'limieslint-plugin-react-hooks7.1.1 — npm paketi- Sinov:
babel-plugin-react-compiler1.0.0 +@babel/core7.29.7, ESLint 10.12.0 (2026-10-13, vaqtinchalik papka) - Kanon:
sinov/18/QADAMLAR.md(#21),natijalar/21-kompilyator.txt,21-b-kompilyator-memo.txt,21-c-faqat-kompilyator.txt,hisobot/18-qarorlar.md
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!