IlmHamroh
JavaScript Full-stack/18-qism. React chuqur19/42-dars16 daqiqa
Mundarija (29)

Kompozitsiya orqali optimallashtirish: memo'siz kamroq render

Qisqacha: memo dan oldin kodning tuzilishini o'zgartiring. Ikki usul ko'p renderni bepul yo'qotadi. Birinchisi — state'ni pastga tushirish: tez o'zgaradigan state uni ishlatadigan kichik komponentga ko'chadi, qolgan sahifa chizilmaydi. Ikkinchisi — children orqali uzatish: state'li o'ram og'ir qismni children sifatida oladi, uni esa ota yasagan, demak o'ram chizilganda u tegilmaydi. Provider'lar ham shunday quriladi: <TemaProvider><App /></TemaProvider> da tema almashganda App umuman chizilmaydi — vazifalar da o'lchangan: 2 render.

Bu darsda

  • State'ni pastga tushirib (colocation), keraksiz renderlarni yo'qotasiz.
  • children orqali uzatish nega memo siz ishlashini Fiber darajasida tushuntirasiz.
  • Tez yangilanadigan qismni alohida komponentga ajratasiz.
  • Provider'ni children naqshi bilan yozib, iste'molchi bo'lmaganlarni himoya qilasiz.
  • Kompozitsiya qachon yordam bermasligini bilasiz.

Oldin bilishingiz kerak: Qayta render sabablari va miflar, children va kompozitsiya, State'ni ko'tarish, Context I.

1. Nega bu kerak?

Qayta render sabablari darsida uchta sababni topdik: o'z state'i, ota render va context. memo faqat bittasini — "ota chizildi" ni — to'xtatadi. Buning narxi ham bor: props solishtiriladi, yangi obyekt yoki funksiya berilsa — ishlamaydi.

Lekin "ota chizildi" sababining o'zini yo'qotsa-chi? Agar og'ir komponent tez o'zgaradigan state'ning ostida bo'lmasa, uni to'xtatishga hojat qolmaydi. Bu — kompozitsiya: komponentlarni boshqacha joylashtirish. React jamoasining tavsiyasi ham shu tartibda: avval tuzilish, keyin memo (react.dev, memo sahifasi, "Minimizing props changes" va "Optimizing with memo" bo'limlari).

Hayotiy o'xshatish: «Bahor» oshxonasida kassada har daqiqada chek chiqadi. Agar kassa oshxona o'rtasida tursa, har chekda hamma oshpaz boshini ko'taradi. Kassani eshik yoniga ko'chirsangiz — oshpazlar ishlayveradi. Hech kimga "e'tibor berma" deb o'rgatish (memo) shart emas.

2. Muammo: tez state yuqorida

2.1 Aksiya matni va og'ir menyu

Jasur aka sahifa tepasidagi aksiya matnini yozadi. Pastda — og'ir menyu (Menu, haqiqiy loyihada yuzlab karta). Matn App ning state'ida. Konsolda Menu chizildi qatorlarini sanang:

jsx
import { useState } from "react";

function Menu() {
  console.log("Menu chizildi");
  return (
    <ul>
      <li>Osh — 35000</li>
      <li>Manti — 30000</li>
    </ul>
  );
}

function App() {
  const [promo, setPromo] = useState("");
  console.log("App:", promo);
  return (
    <main>
      <input
        placeholder="Aksiya"
        value={promo}
        onChange={(e) => setPromo(e.target.value)}
      />
      <p>Bugun: {promo}</p>
      <Menu />
    </main>
  );
}

Konsolda:

text
App: 
Menu chizildi
App: Osh -10%
Menu chizildi
App: Osh -15%
Menu chizildi

Har o'zgarishda Menu qayta chizildi. U promo ni umuman ishlatmaydi — sababi faqat "ota chizildi". Haqiqiy klaviaturada bu har harf degani.

3. State'ni pastga tushirish

3.1 State uni ishlatadiganlar yoniga

promo ni kim ishlatadi? Faqat input va <p>. Demak, state shu ikkisi bilan birga alohida komponentga ko'chadi. Bu state colocation (state'ni yoniga joylash) — state'ni uni ishlatadigan eng pastki umumiy komponentda saqlash:

jsx
import { useState } from "react";

function Menu() {
  console.log("Menu chizildi");
  return (
    <ul>
      <li>Osh — 35000</li>
      <li>Manti — 30000</li>
    </ul>
  );
}

function PromoEditor() {
  const [promo, setPromo] = useState("");
  console.log("PromoEditor:", promo);
  return (
    <>
      <input
        placeholder="Aksiya"
        value={promo}
        onChange={(e) => setPromo(e.target.value)}
      />
      <p>Bugun: {promo}</p>
    </>
  );
}

function App() {
  console.log("App");
  return (
    <main>
      <PromoEditor />
      <Menu />
    </main>
  );
}

Konsolda:

text
App
PromoEditor: 
Menu chizildi
PromoEditor: Osh -10%
PromoEditor: Osh -15%

Menu endi faqat bir marta — birinchi chizishda. App ham qayta chizilmaydi: unda state yo'q. Render PromoEditor dan pastga ketadi, Menu esa uning yonida, ostida emas (Qayta render sabablari dagi "pastga" qoidasi).

3.2 Bu State'ni ko'tarish ga zidmi?

Yo'q, bu o'sha qoidaning ikkinchi yarmi. State'ni ko'tarish darsida qoida shunday edi: state'ni uni ishlatadigan komponentlarning eng yaqin umumiy otasiga qo'ying. Ikki komponent bitta qiymatni ko'rsa — yuqoriga. Faqat bittasi ko'rsa — keraksiz yuqori turmasin, pastga.

Ko'p loyihada state vaqt o'tishi bilan "yuqoriga suzib chiqadi": bir paytlar ikki joyda kerak bo'lgan, keyin bitta joy qolgan, state esa App da qolib ketgan. Davriy savol foydali: "bu state'ni kim o'qiydi?"

Tekshirib ko'ring: Ertaga Jasur aka aksiya matnini menyu sarlavhasida ham ko'rsatishni so'radi. promo qayerda yashashi kerak va Menu yana har harfda chiziladimi?

Javob

Endi promo ni ikki komponent o'qiydi — PromoEditor va Menu. Demak, yana umumiy otaga (App) ko'tariladi va Menu har harfda chiziladi — chunki u endi promo ga haqiqatan bog'liq. Bunda keraksiz render yo'q, kerakli render bor. Agar Menu ning faqat sarlavhasi bog'liq bo'lsa, sarlavhani alohida komponentga ajrating va promo ni faqat unga bering — og'ir ro'yxat qismi baribir chizilmaydi.

3.3 Komponentni ajratish

Xuddi shu usulning yana bir ko'rinishi — komponentni ajratish: tez yangilanadigan kichik qismni o'z komponentiga chiqarish. Masalan, sahifa burchagidagi soat har soniya setNow qiladi. Soat App ichida yozilgan bo'lsa — butun sahifa har soniya chiziladi. <Clock /> ga ajratilsa — faqat u.

Bu vazifalar da allaqachon bor: e'lon taymeri useElon hook'iga, statistika paneli — StatistikaPaneli ga ajratilgan (Custom hooklar I). Lekin diqqat: hook'ga ajratish renderni kamaytirmaydi — hook'ning state'i baribir uni chaqirgan komponentniki. Renderni faqat komponentga ajratish kamaytiradi.

4. Children orqali uzatish

4.1 State og'ir qismni o'raydi

Ba'zan state'ni pastga tushirib bo'lmaydi: u og'ir qismning atrofida kerak. Masalan, menyu fonining rangi — state, menyu esa shu fon ichida:

jsx
import { useState } from "react";

function Menu() {
  console.log("Menu chizildi");
  return (
    <ul>
      <li>Osh — 35000</li>
      <li>Manti — 30000</li>
    </ul>
  );
}

function App() {
  const [color, setColor] = useState("black");
  console.log("App:", color);
  return (
    <div style={{ color }}>
      <button onClick={() => setColor("red")}>Qizil</button>
      <button onClick={() => setColor("green")}>Yashil</button>
      <Menu />
    </div>
  );
}

Konsolda:

text
App: black
Menu chizildi
App: red
Menu chizildi
App: green
Menu chizildi

<div style={{ color }}> va <Menu /> bitta komponentda. Menu ni div dan tashqariga chiqarib bo'lmaydi — u rangni meros oladi.

4.2 Og'ir qism — children

Yechim: rangli o'ramni alohida komponent qilamiz, Menu ni esa unga children sifatida beramiz (children va kompozitsiya):

jsx
import { useState } from "react";

function Menu() {
  console.log("Menu chizildi");
  return (
    <ul>
      <li>Osh — 35000</li>
      <li>Manti — 30000</li>
    </ul>
  );
}

function ColorBox({ children }) {
  const [color, setColor] = useState("black");
  console.log("ColorBox:", color);
  return (
    <div style={{ color }}>
      <button onClick={() => setColor("red")}>Qizil</button>
      <button onClick={() => setColor("green")}>Yashil</button>
      {children}
    </div>
  );
}

function App() {
  console.log("App");
  return (
    <ColorBox>
      <Menu />
    </ColorBox>
  );
}

Konsolda:

text
App
ColorBox: black
Menu chizildi
ColorBox: red
ColorBox: green

Ekranda:

text
QizilYashil
Osh — 35000
Manti — 30000
Qadam Kim chizildi Nega
birinchi chizish App, ColorBox, Menu hammasi yangi
«Qizil» faqat ColorBox o'z state'i; children — o'sha element
«Yashil» faqat ColorBox xuddi shunday

Menu faqat bir marta chizildi — lekin u hali ham rangli div ichida (ekranda rang o'zgaradi). memo yo'q. Qanday?

4.3 Nega ishlaydi

Reconciliation darsini eslang: <Menu /> — oddiy element obyekti. Uni kim yasadi? App — o'z renderida. ColorBox esa uni tayyor holda children props'ida oladi va JSX'ga qo'yadi.

Rang o'zgarganda faqat ColorBox qayta chiziladi (o'z state'i). App chizilmaydi — demak, <Menu /> elementi yangidan yasalmaydi. ColorBox ning yangi renderida children — o'sha obyekt, oldingi renderdagisi. React Fiber'ni ishlayotganda buni ko'radi: element o'sha, props obyekti o'sha (eskiProps === yangiProps) — demak, bu qismni qayta chizishga sabab yo'q. Bu tekshiruv memo siz ham har komponent uchun bor: memo faqat props mazmunini solishtiradi, bu esa props obyektining o'zini.

flowchart TD
  A["App: Menu elementini yasaydi"] --> B["ColorBox: children"]
  B --> C{"Rang o'zgardi"}
  C --> D["ColorBox qayta chiziladi"]
  D --> E{"children o'sha obyektmi?"}
  E -->|"ha: App chizilmadi"| F["Menu tegilmaydi"]
  E -->|"yo'q: App ham chizildi"| G["Menu chiziladi"]

Diagrammaning pastki o'ng shoxiga qarang: agar App ham chizilsa (masalan, App ning o'z state'i o'zgarsa), yangi <Menu /> yasaladi va Menu chiziladi. Kompozitsiya ColorBox ichidagi o'zgarishlardan himoya qiladi, yuqoridagilardan emas.

Maslahat: children — yagona slot emas. Har qanday JSX props ham shunday ishlaydi: <Layout sidebar={<Menu />} header={<Logo />}>. Elementlarni yuqorida yasang, state'li komponentga tayyor holda bering.

Tekshirib ko'ring: ColorBox ichida {children} o'rniga <Menu /> deb to'g'ridan-to'g'ri yozilsa (va App da <ColorBox /> bo'sh bo'lsa), rang o'zgarganda Menu chiziladimi?

Javob

Chiziladi. Endi <Menu /> elementini ColorBox ning o'zi yasaydi — har renderda yangi element, yangi props obyekti. Bu «Children orqali uzatish» dan oldingi holatga qaytish: og'ir qism yana state egasining renderida tug'iladi. Qoida: og'ir elementni state'dan yuqorida yasang.

5. Provider'ni pastga tushirish

5.1 Provider — children li o'ram

Context'da ham aynan shu naqsh. Ko'p loyihada provider'lar App ning eng tepasida, state esa App ning o'zida:

jsx
function App() {
  const [theme, setTheme] = useState("yorug'"); // ❌ butun App
  return (
    <ThemeContext value={{ theme, setTheme }}>
      <Header />
      <Menu />
      <Footer />
    </ThemeContext>
  );
}

Tema almashsa — App chiziladi, demak Header, Menu, Footer va ularning hamma bolalari. Ulardan faqat bittasi temani o'qisa ham.

Yechim — «Children orqali uzatish» ning o'zi: state va context'ni alohida provider komponentiga, ilovani esa children ga:

jsx
import { createContext, use, useState } from "react";

const ThemeContext = createContext(null);

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("yorug'");
  console.log("ThemeProvider:", theme);
  return (
    <ThemeContext value={{ theme, setTheme }}>
      {children}
    </ThemeContext>
  );
}

function ThemeToggle() {
  const { theme, setTheme } = use(ThemeContext);
  console.log("ThemeToggle:", theme);
  return (
    <button onClick={() => setTheme("qorong'i")}>Qorong'i</button>
  );
}

function Menu() {
  console.log("Menu");
  return <p>Osh, Manti</p>;
}

function App() {
  console.log("App");
  return (
    <main>
      <ThemeToggle />
      <Menu />
    </main>
  );
}

export default function Root() {
  return (
    <ThemeProvider>
      <App />
    </ThemeProvider>
  );
}

Konsolda:

text
ThemeProvider: yorug'
App
ThemeToggle: yorug'
Menu
ThemeProvider: qorong'i
ThemeToggle: qorong'i

Bosishdan keyin — atigi ikki qator. ThemeProvider (o'z state'i) va ThemeToggle (context o'qiydi). App va Menu — yo'q: <App /> elementini Root yasagan, ThemeProvider uni children da tayyor holda oldi. Context qiymati har renderda yangi obyekt ({ theme, setTheme }) — lekin bu faqat iste'molchilarga ta'sir qiladi, bu yerda esa iste'molchi bitta.

5.2 Provider qayerda turishi kerak

"Pastga tushirish" provider uchun ikki ma'noda:

  1. Kod sifatida — state'ni App dan provider komponentiga ko'chirish (yuqoridagi misol).
  2. Daraxtda — provider'ni faqat kerakli qismni o'raydigan qilib qo'yish. Savatcha context'i faqat buyurtma sahifasida kerak bo'lsa, uni butun ilova atrofiga emas, shu sahifa atrofiga qo'ying. Kamroq iste'molchi — kamroq render, kod ham o'qilishi oson.

Lekin ehtiyot bo'ling: provider ostidan chiqib ketgan iste'molchi createContext dagi standart qiymatni oladi (bizda null) — Context I dagi "Provider yo'q" xatosi. Shuning uchun vazifalar dagi useTema() null da aniq xato tashlaydi.

6. Qachon yordam bermaydi

Kompozitsiya — birinchi qadam, lekin har joyda emas:

Holat Nega kompozitsiya yetmaydi Keyingi qadam
state'ni ko'p joy yozadi va o'qiydi pastga tushirib bo'lmaydi o'lchang; kerak bo'lsa memo
og'ir komponent state'ga haqiqatan bog'liq render kerakli, keraksiz emas useDeferredValue, virtualizatsiya
ro'yxatdagi 1 000 qatordan bittasi o'zgardi qatorlar bitta massivdan memo + barqaror obyektlar
context'ni ko'p komponent o'qiydi, qiymat obyekt har iste'molchi chiziladi qiymatni useMemo, context'ni bo'lish

Uchinchi qator — vazifalar dagi 18 056 renderning holati. Ro'yxat vazifalar massividan chiziladi, bitta vazifa o'zgarsa massiv yangi. Bunda tuzilishni o'zgartirish yordam bermaydi — keyingi darsning memo si kerak.

7. Vazifalar qadami: tema — kompozitsiya ishda (o'lchov, commit yo'q)

7.1 Kanon kodi

Kanonda #19 alohida qadam emas — holat 20 ning bir qismi (QADAMLAR.md: "#19 R-64 kompozitsiya — yuqoridagi tema misoli"). Kompozitsiya 17-qismdan beri bor, biz faqat uni o'lchadik. main.tsx (holat 12):

tsx
flushSync(() => {
  createRoot(ildiz, ildizSozlamasi).render(
    <StrictMode>
      <TemaProvider>
        <App
          boshlangichRoyxat={yukla() ?? boshlangichVazifalar}
          qoralama={qoralamaniOl()}
        />
      </TemaProvider>
    </StrictMode>,
  );
});

<App … /> elementini modul kodi yasaydi va TemaProvider ga children qilib beradi — «Provider — children li o'ram» dagi Root ning aynan o'zi. TemaProvider (kontekst/TemaKonteksti.tsx, Context II da yozilgan):

tsx
export function TemaProvider({ children }: { children: ReactNode }) {
  // Funksiya — localStorage faqat birinchi renderda o'qiladi
  const [tanlov, setTanlov] = useState(saqlanganTanlov);
  …
  // React 19: <Context value> — .Provider yozish shart emas.
  // Qiymat har renderda yangi obyekt — iste'molchilar ham qayta
  // chiziladi; bizda bitta kichik iste'molchi, o'lchash va memo —
  // 18-qism
  return (
    <TemaKonteksti value={{ tanlov, tanla }}>{children}</TemaKonteksti>
  );
}

Izoh qatorlari telefonga sig'ishi uchun qayta bo'lindi, return qatori — kanondagidek. 17-qismda yozilgan izoh va'da bergan edi: "o'lchash va memo — 18-qism". Endi o'lchaymiz.

7.2 O'lchov va qaror

olchov/renderlar.mjs, holat 12, 1 000 vazifa (natijalar/18-renderlar-12.txt):

text
tema tanlovi (Context)                 commit  1, render     2 — TemaProvider×1, TemaTanlov×1

Bitta commit, ikki render: TemaProvider (o'z state'i) va TemaTanlov (yagona iste'molchi). App — 730 qatorli komponent, ichida 1 000 vazifali ro'yxat — umuman chizilmadi. Holat 20 dagi qayta o'lchovda ham o'sha (20-renderlar.txt).

Qaror: qiymatni useMemo ga o'rash kerak emas. Iste'molchi bitta va u tema almashganda baribir chizilishi kerak (u tanlovni ko'rsatadi). useMemo faqat kod qo'shardi. Bu «"Qayta render — yomon" mifi» dagi tartib: avval o'lchov, keyin qaror — va ba'zan qaror "hech narsa qilmaslik".

7.3 Qolgan joylar

Xuddi shu o'lchovdagi boshqa satr: e'lon o'chishi — 17 render (App va uning memo siz bolalari). E'lon state'i (useElon) App da: uni App ning 16 joyi yozadi (elonQil(…) — saqlash, o'chirish, import, eksport…). Pastga tushirib bo'lmaydi — yozuvchilar App da. 17 render esa arzon: ro'yxat memo bilan himoyalangan (useDeferredValue dagi memo(VazifaRoyxati)). Kanon unga tegmadi — to'g'ri qaror.

8. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
input yozganda butun sahifa chiziladi input state'i App da state'ni input komponentiga
custom hook'ga chiqardim, render kamaymadi hook state'i chaqiruvchiniki komponentga ajrating
children bilan ham og'ir qism chizilyapti element state egasining ichida yasalgan elementni yuqorida yasang
provider'dagi state o'zgarsa hamma chiziladi state App da, provider faqat qiymatni uzatadi provider komponenti + children
context ostidan chiqqan komponent null oldi provider juda pastga tushirildi provider'ni iste'molchilarning umumiy otasiga
tuzilishni o'zgartirdim, o'zgarish yo'q komponent state'ga haqiqatan bog'liq useDeferredValue, memo, virtualizatsiya

9. Mashqlar

Mashqlar kurs/mashqlar/18/19-kompozitsiya/ da. Har yechimni «Ishga tushir» bilan sinang.

1-mashq (oson): qaysi usul?

  • Qidiruv maydoni state'i App da, faqat maydon ishlatadi:
  • Modal oynaning open state'i og'ir forma atrofida (<dialog open> ichida forma):
  • Soat har soniya yangilanadi, App ichida yozilgan:
Yechim

Birinchisida state'ni ishlatadigan yagona joy bor — state shu yerga ko'chadi. Ikkinchisida state og'ir qismni o'raydi — o'ram komponenti forma'ni children sifatida oladi. Uchinchisi — birinchining varianti: tez yangilanadigan kichik qism o'z komponentiga chiqadi, state bilan birga.

2-mashq (o'rta): buyurtma vaqti

App da now state'i (soat) va og'ir OrderTable. «Tik» tugmasi soniyani oshiradi (haqiqiy ilovada — setInterval). Hozir OrderTable har «Tik» da chiziladi. Kodni qayta tuzing: OrderTable faqat bir marta chizilsin, soat esa yangilansin. Kutilgan konsol — pastda.

jsx
import { useState } from "react";

function OrderTable() {
  console.log("OrderTable chizildi");
  return <p>Buyurtmalar: 12 ta</p>;
}

function App() {
  const [now, setNow] = useState(0);
  return (
    <main>
      <p>Soniya: {now}</p>
      <button onClick={() => setNow(now + 1)}>Tik</button>
      <OrderTable />
    </main>
  );
}

Konsolda:

text
OrderTable chizildi
OrderTable chizildi
OrderTable chizildi
Yechim
jsx
import { useState } from "react";

function OrderTable() {
  console.log("OrderTable chizildi");
  return <p>Buyurtmalar: 12 ta</p>;
}

function Clock() {
  const [now, setNow] = useState(0);
  console.log("Clock:", now);
  return (
    <>
      <p>Soniya: {now}</p>
      <button onClick={() => setNow(now + 1)}>Tik</button>
    </>
  );
}

function App() {
  return (
    <main>
      <Clock />
      <OrderTable />
    </main>
  );
}

Konsolda:

text
Clock: 0
OrderTable chizildi
Clock: 1
Clock: 2

Ekranda:

text
Soniya: 2
Tik
Buyurtmalar: 12 ta

now va uni ishlatadigan ikki element Clock ga ko'chdi. App endi state'siz — u faqat bir marta chiziladi, OrderTable ham. Haqiqiy setInterval bilan ham xuddi shunday: effekt Clock ichida (useEffect III: cleanup).

3-mashq (qiyin): retsept paneli

Retsept paneli: sarlavha, «Rang» tugmasi (highlight state'i sarlavhani qizil qiladi) va ichida og'ir Recipe. Hozir hammasi bitta komponentda va Recipe har bosishda chiziladi. Talab: qayta ishlatiladigan Panel komponentini yozing (title va children props). Recipe panel ichida qolsin, lekin «Rang» bosilganda chizilmasin. Faqat children naqshi bilan, memo siz.

jsx
import { useState } from "react";

function Recipe() {
  console.log("Recipe chizildi");
  return <p>Osh: guruch, sabzi, go'sht</p>;
}

function App() {
  const [highlight, setHighlight] = useState(false);
  return (
    <section>
      <h2 style={{ color: highlight ? "red" : "black" }}>Retsept</h2>
      <button onClick={() => setHighlight(!highlight)}>Rang</button>
      <Recipe />
    </section>
  );
}
Yechim
jsx
import { useState } from "react";

function Recipe() {
  console.log("Recipe chizildi");
  return <p>Osh: guruch, sabzi, go'sht</p>;
}

function Panel({ title, children }) {
  const [highlight, setHighlight] = useState(false);
  console.log("Panel:", highlight);
  return (
    <section>
      <h2 style={{ color: highlight ? "red" : "black" }}>{title}</h2>
      <button onClick={() => setHighlight(!highlight)}>Rang</button>
      {children}
    </section>
  );
}

function App() {
  return (
    <Panel title="Retsept">
      <Recipe />
    </Panel>
  );
}

Konsolda:

text
Panel: false
Recipe chizildi
Panel: true
Panel: false

highlight endi Panel da, <Recipe /> esa App da yasaladi va children bo'lib keladi. Panel chizilganda children — o'sha element, Recipe tegilmaydi. Bonus: Panel endi qayta ishlatiladigan komponent — title va children bilan istalgan mazmunni o'raydi. Kompozitsiya ko'pincha shunday: tezlik bilan birga yaxshiroq API ham beradi (Compound komponentlar darsida davomi).

4-mashq: vazifalar — kim state'ni o'qiydi?

vazifalar ning App.tsx ida (holat 20) har useState/useReducer/useOptimistic uchun yozing: uni qaysi komponentlar o'qiydi va qaysilar yozadi. Qaysi biri pastga tushishi mumkin edi? e'lon haqidagi «Qolgan joylar» bo'limidagi xulosani o'zingiz tekshiring: elonQil( necha joyda chaqiriladi? Kod o'zgartirmang.

Yechim

grep -c "elonQil(" src/App.tsx — kanonda (holat 20) 16 qator, har birida bitta chaqiruv. Yozuvchilar App ichidagi ishlovchilar, o'quvchi — Bildirishnoma. Bunday state'ni pastga tushirib bo'lmaydi: yozuvchilarni ham ko'chirish kerak bo'lardi. Muqobil — tashqi do'kon (useSyncExternalStore, useSyncExternalStore), shunda faqat Bildirishnoma chiziladi. Lekin 17 render (1 commit) — o'lchovda sezilmaydi, murakkablik esa oshadi. Tahlilning o'zi — mashqning maqsadi: har state uchun "kim o'qiydi?" savoliga javob.

10. Real ishda

  • Layout komponentlari: Layout, Card, Modal, Drawer — deyarli hammasi children yoki slot props bilan yoziladi: o'ram o'z holatini (ochiq/yopiq, rang) boshqaradi, mazmun esa tashqaridan keladi.
  • Provider'lar: Next.js va boshqa freymvorklarda <Providers>{children}</Providers> naqshi standart — aynan shu sababdan.
  • Forma kutubxonalari: React Hook Form kabi kutubxonalar input state'ini input yonida saqlaydi (uncontrolled) — butun forma har harfda chizilmasligi uchun (keyingi qismlarda).
  • Intervyu savollari: "memo siz renderni qanday kamaytirasiz?", "Nega children qayta chizilmaydi?", "State colocation nima?", "Provider'ni qayerga qo'yasiz?".

Xulosa

  • memo dan oldin — tuzilish: "ota chizildi" sababini yo'qotish uni to'xtatishdan arzon.
  • State colocation: state'ni uni o'qiydigan eng pastki komponentga; tez qismni alohida komponentga ajrating (hook'ga emas).
  • children orqali uzatish: og'ir element state egasidan yuqorida yasaladi — o'ram chizilganda u o'sha obyekt, React tegmaydi.
  • Provider — children li komponent: tema almashganda faqat provider va iste'molchilar chiziladi.
  • vazifalar: tema — 1 commit, 2 render (App umuman chizilmadi), useMemo kerak emas; e'lon state'i 16 joyda yoziladi — pastga tushmaydi, 17 render esa arzon.

Keyingi dars: memo, useMemo, useCallback: qachon va qanday — kompozitsiya yetmaganda: vazifalar ro'yxatida 18 056 → 68 render.

Manbalar

  • React: memo — "Minimizing props changes" — react.dev/reference/react/memo
  • React: "Passing JSX as children" — react.dev/learn/passing-props-to-a-component
  • Dan Abramov, "Before You memo()" (2021-02-23) — overreacted.io/before-you-memo
  • Kanon: sinov/18/QADAMLAR.md (#16–#20), natijalar/18-renderlar-12.txt, natijalar/20-renderlar.txt
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Kompozitsiya orqali optimallashtirish: memo'siz kamroq render — IlmHamroh