IlmHamroh
JavaScript Full-stack/18-qism. React chuqur21/42-dars19 daqiqa
Mundarija (31)

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, useCallback va memo ning 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 uni vazifalar da o'lchadik: katak 32 → 24 ms, lekin har yuklashda +6.6 KB gzip, build ×1.7 va tsc turlar 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.
  • vazifalar dagi 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:

jsx
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:

jsx
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 — "oldingi label bilan bir xilmi?" Bir xil bo'lsa — eski element ($[1]), aks holda yangisi yasaladi va keshga yoziladi.
  • Tugmadagi inline funksiya () => console.log(dish) — endi dish o'zgarmasa o'sha funksiya va o'sha element. Bu — siz qo'lda useCallback bilan 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):

bash
npm install -D @rolldown/plugin-babel @babel/core \
  babel-plugin-react-compiler
js
// 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:

text
CompileSkip

Komponent 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

jsx
export function Timer() {
  const renders = useRef(0);
  renders.current += 1;
  return <p>{renders.current}</p>;
}

Logger:

text
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

jsx
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:

jsx
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:

text
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: addLagmon ni 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):

text
  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/refs

Va komponent ichida e'lon qilingan komponent (Reconciliation):

text
  6:15  error  Error: Cannot create components during render
…                                    react-hooks/static-components

Math.random() render ichida:

text
  2:29  error  Error: Cannot call impure function during render
…                                    react-hooks/purity

Chiqishlar 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:

tsx
  return vazifalar.map((vazifa) => (
    <VazifaQatori
      key={vazifa.id}
      vazifa={vazifa}
      sorov={sorov}
      tahrirda={vazifa.id === tahrirId}
    />
  ));

Xuddi shu shakldagi kichik komponentni kompilyatorga berdik:

jsx
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):

text
CompileSuccess TaskRow

TaskList — 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:

jsx
  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 TaskRow ichidagi <li> kesh bilan saqlanadi. Ro'yxat qayta hisoblanganda TaskRow funksiyasi 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
Katak bosilishi, 1 000 va 10 000 vazifa (mediana)
  • 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 (App ning memo siz 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, VazifaQatori ga esa memo() 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:

  1. Build ×1.7: 1 845 / 1 681 / 1 753 ms → 3 115 / 3 049 / 2 960 ms (uch marta).
  2. tsc -b yiqildi — kutubxona turlarida. Babel 7 bilan: @rolldown/plugin-babel turlari @types/babel__core dan InputOptions ni topmadi — va bu turni loyihadan tashqaridagi D:/Ilmhamroh/node_modules dan olgan edi. Kompilyatorning .d.ts i PerformanceMeasure ni so'radi, tsconfig.node.json da esa DOM lib yo'q. Babel 8 bilan — boshqa ikki xato. Ishlatish uchun skipLibCheck: true kerak bo'lardi — ya'ni kutubxona turlarini tekshirmaslik (tsconfig frontend loyihada).
  3. 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):

text
Lag'mon qo'sh
Jami: 3
Osh
Manti
Lag'mon
Yechim
jsx
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:

text
Lag'mon qo'sh
Jami: 3
Osh
Manti
Lag'mon

Yangi 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).

jsx
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
jsx
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:

text
har xil talonlar: 1
har xil talonlar: 1
har xil talonlar: 1

useState(() => …) — 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 memo yozish kamayadi — lekin uni o'qish va kompilyator qachon ishlamasligini bilish qoladi.
  • Mavjud loyihalar: avval eslint-plugin-react-hooks ning kompilyator qoidalari yoqiladi va xatolar tuzatiladi, keyin compilationMode: "annotation" bilan bittalab.
  • Kod ko'rigi: "bu yerda useMemo kerakmi?" 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, memo kerakmi?", "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/useCallback ni 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 va return massiv.map(…) qaytaradigan funksiyani komponent deb tanimasligi mumkin — ro'yxatlarda qo'lda memo + o'sha obyektlar kerak.
  • vazifalar: B (kompilyator + qo'lda) katak 32 → 24 ms, lekin +6.6 KB gzip, build ×1.7, skipLibCheck kerak; 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-react 6.1.2 README — "React Compiler" bo'limi
  • eslint-plugin-react-hooks 7.1.1 — npm paketi
  • Sinov: babel-plugin-react-compiler 1.0.0 + @babel/core 7.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
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
React Compiler: avtomatik memoizatsiya — va nega biz uni o'lchab, qo'shmadik — IlmHamroh