IlmHamroh
JavaScript Full-stack/17-qism. React asoslari10/45-dars19 daqiqa
Mundarija (25)

Pure komponentlar va render qoidasi: React nega StrictMode'da ikki marta chaqiradi

Qisqacha: React komponenti toza (pure) bo'lishi kerak: bir xil props bilan har doim bir xil JSX qaytarsin. Chizish paytida u tashqaridagi hech narsani o'zgartirmasin — global o'zgaruvchi, props'dagi massiv, document.title yoki server. Sababi: komponentni React o'zi, xohlagan paytda va xohlagancha marta chaqiradi. Ish bajarish (saqlash, yuborish, DOM'ga tegish) — hodisa ishlovchilarida yoki effektlarda. Komponent ichida yangi yaratilgan massivni o'zgartirish esa mumkin. Dev rejimda <StrictMode> har komponentni ataylab ikki marta chaqirib, toza emasini fosh qiladi.

Bu darsda

  • Toza komponentning ikki qoidasini aytib bera olasiz va toza emasini ko'rib taniysiz.
  • Render paytidagi side effect qanday xatoga olib kelishini jonli ko'rasiz.
  • Qaysi mutatsiya taqiqlangan, qaysi biri (lokal) ruxsat etilganini ajratasiz.
  • StrictMode nima qilishini va nega konsolda yozuvlar ikki marta chiqishini tushuntira olasiz.
  • Toza bo'lmagan kodni eslint-plugin-react-hooks bilan ushlaysiz.

Oldin bilishingiz kerak: Pure funksiya va side effect, Props: komponentga ma'lumot uzatish, Ro'yxatlarni render qilish va key.

1. Nega bu kerak?

Pure funksiya va side effect darsida ikki xil funksiyani ko'rgandik. Toza funksiya — bir xil kirishga doim bir xil natija va tashqariga ta'sirsiz: narxniHisobla(2, 35000) doim 70000. Toza bo'lmagani — tashqaridagi narsani o'zgartiradi yoki tashqi narsaga qarab har safar boshqa natija beradi. O'sha darsda React'ga va'da bergan edik: "komponentlar toza bo'lishi shart".

Nega aynan React'da bu shunchalik muhim? Chunki komponentni siz chaqirmaysiz. Komponentlar darsida ko'rdik: <Cup /> faqat "buyurtma qog'ozi", funksiyani React chaqiradi. Qachon chaqirishni ham React hal qiladi. Ota qayta chizilsa — chaqiradi. Ba'zan chizishni boshlab, to'xtatib, qaytadan chaqiradi. Dev rejimda tekshiruv uchun ikki marta chaqiradi. Komponent har chaqiruvda nimanidir o'zgartirsa, natija "necha marta chaqirilgani"ga bog'liq bo'lib qoladi.

Hayotiy o'xshatish: oshpaz va retsept. Retsept bo'yicha osh pishirish — toza: bir xil masalliq, bir xil osh. Lekin oshpaz har safar retseptni o'qiganda omborga borib, bitta qop guruch ochsa-chi? "Retseptni ikki marta o'qib qo'ydim" — omborda ikki qop ochilib yotadi. Retseptni o'qish zararsiz bo'lishi kerak. Omborga borish — alohida ish, aniq paytda qilinadi.

2. Toza komponent: ikki qoida

2.1 Qoidalar

  1. Bir xil kirish — bir xil natija. Bir xil props (keyinroq — state va context) bilan komponent doim bir xil JSX qaytaradi. Bu xususiyat idempotentlik deyiladi: necha marta chaqirsangiz ham, natija o'sha.
  2. Render paytida tashqariga ta'sir yo'q. Komponent chaqirilgunga qadar mavjud bo'lgan narsani o'zgartirmaydi: global o'zgaruvchi, props, document, localStorage, server.

Siz yozgan komponentlarning deyarli hammasi allaqachon toza:

jsx
function OrderLine({ dish, price, count }) {
  const total = price * count;
  return (
    <li>
      {dish} × {count} = {total} so'm
    </li>
  );
}

function App() {
  return (
    <ul>
      <OrderLine dish="Osh" price={35000} count={2} />
      <OrderLine dish="Osh" price={35000} count={2} />
    </ul>
  );
}

Ekranda:

text
Osh × 2 = 70000 so'm
Osh × 2 = 70000 so'm

total — komponent ichida hisoblangan yangi o'zgaruvchi, tashqariga ta'siri yo'q. Bir xil props — bir xil qator. Buni UI = f(state) formulasining "f" qismi deb tasavvur qiling: matematik funksiya kabi.

2.2 Toza bo'lmagan komponent

Sardor «Bahor» choyxonasi uchun piyolalarga raqam qo'ymoqchi bo'ldi: har piyola — keyingi mehmon. Raqamni global o'zgaruvchida saqladi:

jsx
let guest = 0;

function Cup() {
  guest = guest + 1; // ❌ tashqaridagi o'zgaruvchi o'zgaryapti
  return <p>Piyola: {guest}-mehmon uchun</p>;
}

function App() {
  return (
    <>
      <Cup />
      <Cup />
      <Cup />
    </>
  );
}

Ekranda:

text
Piyola: 1-mehmon uchun
Piyola: 2-mehmon uchun
Piyola: 3-mehmon uchun

To'g'ri ko'rinadi. Lekin bu tasodif: natija Cup necha marta chaqirilganiga bog'liq. Bitta <Cup /> — bitta chaqiruv bo'lsa, raqamlar to'g'ri. React esa bunday va'da bermaydi. Ota qayta chizilsa, uchala Cup yana chaqiriladi — va raqamlar 4, 5, 6 bo'lib ketadi, mehmonlar esa o'sha uchta.

3. StrictMode tuzoqni fosh qiladi

3.1 Ikki marta chaqiruv

Birinchi React loyiha darsida main.tsx dagi <StrictMode> ni ko'rgandik va o'lchagandik: dev rejimda komponent ikki marta chaqiriladi. Endi nega ekanini ko'ramiz. O'sha Cup, lekin StrictMode ichida:

jsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

let guest = 0;

function Cup() {
  guest = guest + 1;
  console.log("Cup chaqirildi, guest =", guest);
  return <p>Piyola: {guest}-mehmon uchun</p>;
}

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <Cup />
    <Cup />
    <Cup />
  </StrictMode>
);

Konsolda:

text
Cup chaqirildi, guest = 1
Cup chaqirildi, guest = 2
Cup chaqirildi, guest = 3
Cup chaqirildi, guest = 4
Cup chaqirildi, guest = 5
Cup chaqirildi, guest = 6

Ekranda:

text
Piyola: 2-mehmon uchun
Piyola: 4-mehmon uchun
Piyola: 6-mehmon uchun

Uch komponent — olti chaqiruv. React har birini ikki marta chaqirdi va ikkinchi natijani chizdi. Toza komponentda ikkala natija bir xil bo'lardi va siz hech narsani sezmasdingiz. Cup esa har chaqiruvda guest ni o'zgartirdi — ekranda 2, 4, 6. Xato darhol ko'rinadi.

Chaqiruv guest (oldin → keyin) Natija
1-Cup, birinchi 0 → 1 tashlab yuboriladi
1-Cup, ikkinchi 1 → 2 "2-mehmon" — chiziladi
2-Cup, birinchi 2 → 3 tashlab yuboriladi
2-Cup, ikkinchi 3 → 4 "4-mehmon" — chiziladi

StrictMode xatoni yaratmaydi — u bor xatoni ko'rinadigan qiladi. Production'da komponent bir marta chaqiriladi va 1, 2, 3 chiqadi. Lekin ertaga ota qayta chizilganda yoki React chizishni to'xtatib qayta boshlaganda, o'sha xato production'da ham chiqadi — kutilmagan joyda va qayta takrorlab bo'lmaydigan holda.

3.2 Brauzer konsolida

Brauzerda (React 19) ikkinchi chaqiruvdagi console.log lar xiraroq rangda chiqadi — "bu StrictMode'ning tekshiruv chaqiruvi" degani. Saytdagi natija oynasi esa ularni oddiy ko'rinishda chiqaradi. Muhimi: ikki marta chiqqan log — xato emas, tekshiruv. Xato — ikki chaqiruvning natijasi farq qilishi.

Diqqat: "Konsolda hamma narsa ikki marta chiqyapti" deb StrictMode ni olib tashlamang (Birinchi React loyiha dagi maslahat). U topgan xato baribir bor — faqat yashirinadi.

3.3 StrictMode yana nimani tekshiradi

Tekshiruv Nimani ushlaydi Qaysi darsda
Komponentni ikki marta chaqirish render paytidagi side effect shu dars
Effektlarni ikki marta ulash tozalanmagan obuna, taymer Effekt hayot sikli va StrictMode
Ref callback'larni ikki marta tozalanmagan DOM ishlari useRef II
Eskirgan API'lar eski usulda yozilgan kod React 18 dan 19 ga

Hammasi faqat dev rejimda. Production build'da StrictMode hech narsa qilmaydi va tezlikka ta'sir qilmaydi. vazifalar da ham ikkala React oroli — #izoh va ro'yxat — <StrictMode> ichida chiziladi.

Tekshirib ko'ring: StrictMode ichidagi toza OrderLine (yuqoridagi) har chizishda necha marta chaqiriladi? Ekranda farq bormi?

Javob

Dev rejimda — ikki marta, production'da — bir marta. Ekranda farq yo'q: ikkala chaqiruv ham 70000 hisoblaydi va bir xil JSX qaytaradi. Toza komponent uchun ikki marta chaqiruv bilinmaydi — aynan shuning uchun StrictMode bu usulni tanlagan.

4. Render paytidagi side effect'lar

4.1 Props'dagi massivni o'zgartirish

Eng yashirin xato — props'dagi massiv yoki obyektni joyida o'zgartirish. Bir menyu ikki komponentga berilgan: biri alifbo bo'yicha, biri asl tartibda ko'rsatadi:

jsx
const menu = ["Osh", "Manti", "Choy"];

function SortedMenu({ items }) {
  items.sort(); // ❌ ota komponentning massivi o'zgaradi
  return <p>Alifbo: {items.join(", ")}</p>;
}

function OriginalMenu({ items }) {
  return <p>Asl tartib: {items.join(", ")}</p>;
}

function App() {
  return (
    <>
      <SortedMenu items={menu} />
      <OriginalMenu items={menu} />
    </>
  );
}

Ekranda:

text
Alifbo: Choy, Manti, Osh
Asl tartib: Choy, Manti, Osh

"Asl tartib" buzildi. Sababi: sort() massivni joyida o'zgartiradi (sort va taqqoslash funksiyasi). Bu yerda esa items va menu — bitta massiv (havola semantikasi). Ya'ni SortedMenu o'zining props'ini emas, butun ilovaning ma'lumotini buzdi. Props darsida React props obyektini muzlatishini ko'rgandik, lekin u sayoz muzlatish. Ya'ni props.items = … deb yozib bo'lmaydi, massivning ichini esa o'zgartirish mumkin. Tuzatish — nusxa bilan ishlaydigan metod:

jsx
const menu = ["Osh", "Manti", "Choy"];

function SortedMenu({ items }) {
  const sorted = items.toSorted(); // ✅ yangi massiv
  return <p>Alifbo: {sorted.join(", ")}</p>;
}

function OriginalMenu({ items }) {
  return <p>Asl tartib: {items.join(", ")}</p>;
}

function App() {
  return (
    <>
      <SortedMenu items={menu} />
      <OriginalMenu items={menu} />
    </>
  );
}

Ekranda:

text
Alifbo: Choy, Manti, Osh
Asl tartib: Osh, Manti, Choy

Ro'yxatlar va key darsida toSorted ni tanlaganimizning sababi shu edi.

4.2 Har chaqiruvda boshqa natija: vaqt va tasodif

Qoidaning birinchi qismi — "bir xil kirish — bir xil natija" — boshqacha ham buziladi:

jsx
function LuckyDish() {
  // ❌ har chaqiruvda boshqa taom
  const index = Math.floor(Math.random() * 3);
  return <p>Bugungi taklif: {["Osh", "Manti", "Somsa"][index]}</p>;
}

Bu komponent tashqariga hech narsa yozmaydi, lekin baribir toza emas. Props o'zgarmasa ham, har qayta chizishda taklif almashib turadi. Mijoz menyuni o'qiyotganda "Osh" "Manti" ga aylanib qoladi. Date.now() va new Date() ham shunday: natija chaqiruv vaqtiga bog'liq. Serverda oldindan chizilgan sahifada (SSR — server-side rendering, Next.js qismida) bu yana bir xato beradi: server bir taomni chizadi, brauzer boshqasini.

Yechim — tasodifiy yoki vaqtga bog'liq qiymatni render'dan tashqarida bir marta olish va props yoki state bilan berish. Masalan, "bugungi taklif" serverdan keladi yoki ilova ochilganda bir marta tanlanadi.

4.3 DOM'ga va tashqi tizimlarga tegish

jsx
function OrdersPage({ count }) {
  document.title = `Buyurtmalar (${count})`; // ❌ render paytida DOM
  localStorage.setItem("oxirgi", String(count)); // ❌ saqlash
  fetch("/api/korildi", { method: "POST" }); // ❌ serverga so'rov
  return <h1>Buyurtmalar: {count}</h1>;
}

Uch qatorning uchalasi ham "ish": sahifa sarlavhasini o'zgartirish, saqlash, serverga yozish. StrictMode'da har biri ikki marta bajariladi. Production'da esa React necha marta chizsa, shuncha marta — ya'ni oldindan aytib bo'lmaydi. Server bir ko'rishni uch marta yozib qo'yishi mumkin.

Bunday ishlar qayerda bajariladi?

flowchart LR
  E["Hodisa: bosish, yozish"] --> H["Ishlovchi: ish bajaradi"]
  H --> S["Holat o'zgaradi"]
  S --> R["Render: faqat hisoblaydi"]
  R --> C["React DOM'ni yangilaydi"]
  C -. "tashqi tizim bilan sinxron" .-> F["Effekt"]

Diagrammani chapdan o'qing. Ish — hodisa ishlovchisida: tugma bosildi → saqlash, yuborish (Hodisalarni boshqarish). Render faqat hisoblaydi. "Ekran chizilgandan keyin tashqi tizimni moslash" (sahifa sarlavhasi, obuna) — effektda (useEffect I). Render o'rtada — u toza qoladi.

4.4 Lokal mutatsiya — ruxsat

Qoida "hech narsani o'zgartirma" emas, "mavjud narsani o'zgartirma". Komponent ichida shu chaqiruvda yaratilgan massiv yoki obyektni o'zgartirish — mutlaqo toza:

jsx
function Receipt({ items }) {
  const lines = []; // shu chaqiruvda yaratildi
  let total = 0;
  for (const item of items) {
    total += item.price * item.count;
    lines.push(
      <li key={item.id}>
        {item.dish} × {item.count}
      </li>
    );
  }
  return (
    <>
      <ul>{lines}</ul>
      <p>Jami: {total} so'm</p>
    </>
  );
}

function App() {
  const order = [
    { id: 1, dish: "Osh", price: 35000, count: 2 },
    { id: 2, dish: "Ko'k choy", price: 5000, count: 1 },
  ];
  return <Receipt items={order} />;
}

Ekranda:

text
Osh × 2
Ko'k choy × 1
Jami: 75000 so'm

lines.push va total += — o'zgartirish, lekin lines va total har chaqiruvda noldan yaratiladi. Tashqaridan ularni hech kim ko'rmaydi. Ikki marta chaqirilsa — ikki marta bir xil massiv va bir xil son. Bu lokal mutatsiya (local mutation). vazifalar dagi BelgilanganMatn ham aynan shunday ishlaydi (Shartli render darsida yozganmiz): const qismlar = [] va qismlar.push(…).

O'zgartirilayotgan narsa Qachon yaratilgan Toza?
const lines = [] → push shu chaqiruvda ha
props.items → sort() ota komponentda yo'q
modul darajasidagi let guest fayl yuklanganda yo'q
document.title brauzerda yo'q

Tekshirib ko'ring: function Menu({ items }) { const copy = [...items]; copy.sort(); return <p>{copy.join(", ")}</p>; } — toza komponentmi?

Javob

Ha. copy — shu chaqiruvda yaratilgan yangi massiv (spread — sayoz nusxa). Uni saralash — lokal mutatsiya, items ga tegmaydi. Bu toSorted() ning eski yozilishi — ikkalasi ham to'g'ri. Faqat bir narsani eslang: sayoz nusxada ichidagi obyektlar o'sha-o'sha. copy[0].price = 0 yozilsa, otaning obyekti o'zgaradi — bu State III darsining mavzusi.

5. Linter toza emasni topadi

StrictMode xatoni ishga tushirgandan keyin ko'rsatadi. Linter esa kod yozilayotgandayoq ogohlantiradi. vazifalar ga ulangan eslint-plugin-react-hooks 7.1.1 da toza bo'lmagan kod uchun bir nechta qoida bor. Ular React Compiler'ning tahliliga asoslangan (React Compiler — 18-qismda). Bitta faylda to'rtta komponentni tekshirdik: Cup, LuckyDish, SortedMenu va document.title yozadigan Title:

bash
npx eslint Toza.jsx

Chiqish (ESLint 10.12.0; kod parchalari olib tashlangan). Har xato uch qismdan iborat: boshida qator:ustun va qisqa sarlavha, o'rtada izoh, oxirida qoida nomi (react-hooks/…). Avval qoida nomlariga qarang:

text
   4:3   error  Error: Cannot reassign variables declared outside of the component/hook

Variable `guest` is declared outside of the component/hook. Reassigning this value during render is a form of side effect, which can cause unpredictable behavior depending on when the component happens to re-render. If this variable is used in rendering, use useState instead. Otherwise, consider updating it in an effect.
  react-hooks/globals

   9:28  error  Error: Cannot call impure function during render

`Math.random` is an impure function. Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render.
  react-hooks/purity

  19:3   error  Error: This value cannot be modified

Modifying a variable defined outside a component or hook is not allowed. Consider using an effect.
  react-hooks/immutability

✖ 3 problems (3 errors, 0 warnings)

Uchta qoida, uchta tarjima:

  • react-hooks/globals — "Komponentdan tashqarida e'lon qilingan o'zgaruvchiga render paytida yangi qiymat yozish — side effect. Komponent qachon qayta chizilishiga qarab natija kutilmagan bo'ladi. Ekranda ishlatilsa — useState ishlating, aks holda effektda yangilang."
  • react-hooks/purity — "Math.random — toza bo'lmagan funksiya. Uni render paytida chaqirish beqaror natija beradi."
  • react-hooks/immutability — "Komponentdan tashqarida aniqlangan narsani o'zgartirish mumkin emas. Effekt ishlating." (document.title.)

E'tibor bering: to'rtinchi komponent — SortedMenu dagi items.sort() — xato bermadi. Linter props ichidagi massiv metodining joyida o'zgartirishini har doim ham ko'ra olmaydi. Shuning uchun uch qatlam birga ishlaydi: siz bilgan qoida, linter va StrictMode.

6. Render va commit — bir qadam oldinga

"Chizish" ni React ikki bosqichga bo'ladi. Buni bilish toza bo'lish nega muhimligini oxirigacha tushuntiradi:

sequenceDiagram
  participant T as Sabab
  participant R as Render
  participant C as Commit
  T->>R: birinchi chizish yoki holat o'zgardi
  R->>R: komponentlarni chaqiradi, JSX yig'adi
  R->>C: yangi va eski daraxt farqi
  C->>C: DOM'ni o'zgartiradi
  • Render — React komponentlaringizni chaqiradi va yangi daraxtni hisoblaydi. Bu faqat hisob-kitob: hali DOM'ga tegilmagan. React bu bosqichni to'xtatishi, tashlab yuborishi, qayta boshlashi mumkin. Shuning uchun u toza bo'lishi shart.
  • Commit — React farqni DOM'ga yozadi. Bu bosqichni React o'zi boshqaradi va u bir marta, oxirigacha bajariladi.

Toza komponentlar React'ga erkinlik beradi: ishni bo'laklarga bo'lish, muhimini oldinga o'tkazish, keraksizini tashlab yuborish (Concurrent rendering). Natijani eslab qolib, qayta hisoblamaslik ham mumkin bo'ladi (memo). Bularning hammasi bitta shartga tayanadi: komponentni chaqirish zararsiz. To'liq zanjir — Render va commit darsida.

7. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
dev'da raqamlar 2, 4, 6 render paytida global hisoblagich ma'lumotdan hisoblang yoki state
boshqa komponentda tartib buzildi props massivida sort(), reverse(), push() toSorted(), spread nusxa
har chizishda boshqa qiymat renderda Math.random(), Date.now() render'dan tashqarida bir marta
so'rov ikki marta ketdi renderda fetch, localStorage hodisada yoki effektda
"konsolda ikki marta" StrictMode — xato emas natijalar farq qilmasa — hammasi joyida
Cannot reassign variables declared outside react-hooks/globals yuqoridagi birinchi qator

8. Mashqlar

Mashqlar kurs/mashqlar/17/10-toza-komponent/ da. Har yechimni «Ishga tushir» bilan sinang.

1-mashq (oson): toza yoki yo'q?

Har komponent uchun "toza" yoki "toza emas" deb yozing va sababini ayting.

jsx
// A
function Price({ value }) {
  return <b>{value.toLocaleString("uz-UZ")} so'm</b>;
}
// B
let renders = 0;
function Counter() {
  renders++;
  return <p>{renders}</p>;
}
// C
function TagList({ tags }) {
  const sorted = [...tags].sort();
  return <p>{sorted.join(" ")}</p>;
}
// D
function Greeting({ name }) {
  console.log("Greeting:", name);
  return <h2>Salom, {name}!</h2>;
}
// E
function Clock() {
  return <p>{new Date().toLocaleTimeString()}</p>;
}
  • A:
  • B:
  • E:
Yechim
  • A — toza. Faqat props'dan hisoblaydi, hech narsani o'zgartirmaydi.
  • B — toza emas. Modul darajasidagi renders ni o'zgartiradi — StrictMode'da 2, 4, … chiqadi.
  • C — toza. [...tags] — yangi massiv, uni saralash — lokal mutatsiya.
  • D — toza (amalda). console.log — texnik jihatdan side effect, lekin u faqat ishlab chiqishda kuzatish uchun va ilova holatini o'zgartirmaydi. React ham buni kutadi: StrictMode'ning ikkinchi logi aynan shuning uchun xira chiqadi.
  • E — toza emas. Natija vaqtga bog'liq — bir xil props (props yo'q) bilan har chaqiruvda boshqa matn. Soat kerak bo'lsa, vaqt state'da saqlanadi va taymer effektda yangilaydi (useEffect I).

2-mashq (o'rta): buzilgan menyu

Quyidagi ilovada ikki komponent bitta menu ni ishlatadi. CheapestFirst narx bo'yicha arzonidan boshlab ko'rsatadi, TopDish esa menyuning birinchi taomini "Kun taomi" deb e'lon qiladi. Kun taomi osh bo'lishi kerak edi, lekin ekranda "Ko'k choy" chiqyapti. Xatoni toping va tuzating: CheapestFirst ning natijasi o'zgarmasin, "Kun taomi: Osh" chiqsin.

jsx
const menu = [
  { id: 1, name: "Osh", price: 35000 },
  { id: 2, name: "Manti", price: 30000 },
  { id: 3, name: "Ko'k choy", price: 5000 },
];

function CheapestFirst({ items }) {
  items.sort((a, b) => a.price - b.price);
  return (
    <ol>
      {items.map((d) => (
        <li key={d.id}>{d.name}</li>
      ))}
    </ol>
  );
}

function TopDish({ items }) {
  return <p>Kun taomi: {items[0].name}</p>;
}

function App() {
  return (
    <>
      <CheapestFirst items={menu} />
      <TopDish items={menu} />
    </>
  );
}

Ekranda:

text
Ko'k choy
Manti
Osh
Kun taomi: Ko'k choy

Ishora: «Props'dagi massivni o'zgartirish» bo'limi.

Yechim
jsx
const menu = [
  { id: 1, name: "Osh", price: 35000 },
  { id: 2, name: "Manti", price: 30000 },
  { id: 3, name: "Ko'k choy", price: 5000 },
];

function CheapestFirst({ items }) {
  const sorted = items.toSorted((a, b) => a.price - b.price);
  return (
    <ol>
      {sorted.map((d) => (
        <li key={d.id}>{d.name}</li>
      ))}
    </ol>
  );
}

function TopDish({ items }) {
  return <p>Kun taomi: {items[0].name}</p>;
}

function App() {
  return (
    <>
      <CheapestFirst items={menu} />
      <TopDish items={menu} />
    </>
  );
}

Ekranda:

text
Ko'k choy
Manti
Osh
Kun taomi: Osh

sort menu ning o'zini o'zgartirgandi — TopDish chizilganda massivning birinchi elementi allaqachon ko'k choy edi. Xato TopDish da ko'rindi, lekin sababi CheapestFirst da. Toza bo'lmagan komponent xatosining eng yomon tomoni shu: belgi bir joyda, sabab boshqa joyda. toSorted yangi massiv qaytaradi va menu ga tegmaydi.

3-mashq (qiyin): mehmon raqamlari — toza usulda

Cup misolini toza qiling. Talablar:

  • global guest o'zgaruvchisi bo'lmasin;
  • Cup raqamni props'dan olsin: <Cup guest={…} />;
  • App mehmonlar massividan (["Ali", "Malika", "Bobur"]) piyolalar chizsin, raqam — map dagi indeksdan + 1, ismi ham chiqsin;
  • App <StrictMode> ichida chizilsin va Cup ichida console.log bo'lsin — StrictMode'da ham raqamlar 1, 2, 3 qolishini ko'ring.

Bu yerda key sifatida ism yetadi (ismlar takrorlanmaydi). Indeksni esa faqat raqam uchun ishlatamiz — key uchun emas.

text
Piyola №1 — Ali
Piyola №2 — Malika
Piyola №3 — Bobur
Yechim
jsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

function Cup({ guest, name }) {
  console.log("Cup:", guest);
  return (
    <p>
      Piyola №{guest} — {name}
    </p>
  );
}

function App() {
  const guests = ["Ali", "Malika", "Bobur"];
  return (
    <>
      {guests.map((name, index) => (
        <Cup key={name} guest={index + 1} name={name} />
      ))}
    </>
  );
}

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <App />
  </StrictMode>
);

Konsolda:

text
Cup: 1
Cup: 1
Cup: 2
Cup: 2
Cup: 3
Cup: 3

Ekranda:

text
Piyola №1 — Ali
Piyola №2 — Malika
Piyola №3 — Bobur

Har Cup ikki marta chaqirildi (StrictMode) — va ikkala marta ham bir xil raqam. Raqam endi tashqi hisoblagichdan emas, ma'lumotdan (massivdagi o'rindan) kelib chiqadi. Bu — UI = f(state): ekran ma'lumotning funksiyasi, chaqiruvlar soniga bog'liq emas.

4-mashq: vazifalar ga nazar

Bu darsda vazifalar kodi o'zgarmaydi. Ro'yxatlar va key darsida commit qilingan fayllarni oching va uchta savolga javob bering:

  1. BelgilanganMatn.tsx da qismlar.push(...) bor. Bu toza komponent qoidasini buzadimi?
  2. render.tsx da royxatIldizi.render(...) ichida korinadiganlar() chaqiriladi — u holatdan filtrlangan va saralangan massiv qaytaradi. Agar u holat.vazifalar.sort(...) qilganda edi, qanday xavf bo'lardi?
  3. VazifaQatori nega global holat.tahrirId ga qaramaydi, tahrirda props'ini oladi?
Yechim
  1. Yo'q. qismlar har chaqiruvda [] bilan yangidan yaratiladi — bu lokal mutatsiya. StrictMode ikki marta chaqirsa — ikki marta bir xil bo'laklar.
  2. sort joyida o'zgartiradi — har chizishda asl ro'yxat tartibi buzilardi. Saqlash, eksport va server sinxroni ham boshqa tartibni ko'rardi. Shuning uchun korinadiganlar() yangi massiv qaytaradi (filtr va saralash nusxada). Asl holat.vazifalar esa faqat o'qiladi. State III darsida bu readonly bilan majburiy bo'ladi.
  3. Global holatni o'qigan komponent "bir xil props — bir xil natija" qoidasini buzadi: props o'zgarmasa ham, global qiymat o'zgarib qolishi mumkin. Props bilan esa natija faqat kirishga bog'liq — komponentni test qilish ham oson: VazifaRoyxati.test.tsx uni hech qanday global holatsiz chizadi.

9. Real ishda

  • StrictMode — Vite, Next.js va boshqa shablonlarda sukut bo'yicha yoqilgan. Uni o'chirgan kod kod ko'rigida savol uyg'otadi.
  • React Compiler (18-qismda) faqat toza komponentlarni xavfsiz optimallashtira oladi. Toza bo'lmagan kodni kompilyator "o'tkazib yuboradi" yoki buzib qo'yadi. Shuning uchun react-hooks lint qoidalari ham kompilyator tahliliga asoslangan.
  • SSR va hydration (serverdan kelgan tayyor HTML'ni brauzerda React "jonlantirishi") — serverda va brauzerda bir xil komponent bir xil natija berishi shart. Renderdagi Math.random() yoki Date.now() — "hydration mismatch" xatosining eng ko'p uchraydigan sababi.
  • Intervyu savollari: "Pure komponent nima?", "Nega StrictMode komponentni ikki marta chaqiradi?", "Komponent ichida massivni push qilsa bo'ladimi?", "Side effect'ni qayerga yozasiz?".

Xulosa

  • Toza komponent: bir xil props — bir xil JSX, va render paytida tashqaridagi hech narsa o'zgarmaydi.
  • Render paytida global o'zgaruvchi, props ichidagi massiv, document va tashqi tizimlarga tegmang; Math.random, Date.now ham natijani beqaror qiladi.
  • Shu chaqiruvda yaratilgan massiv yoki obyektni o'zgartirish (lokal mutatsiya) — ruxsat.
  • StrictMode dev'da har komponentni ikki marta chaqiradi: toza komponentda farq bilinmaydi, toza bo'lmaganida xato ochiladi.
  • Ish — hodisa ishlovchisida, tashqi tizim bilan sinxronlash — effektda; render faqat hisoblaydi.
  • react-hooks/globals, purity, immutability qoidalari ko'p holatni yozish paytidayoq ushlaydi — lekin hammasini emas.

Keyingi dars: Hodisalarni boshqarish — ish bajariladigan joy: onClick, onChange, onSubmit va vazifalar qatorlaridagi tugmalarni React'ga o'tkazamiz.

Manbalar

  • React: "Keeping Components Pure" — react.dev/learn/keeping-components-pure
  • React: "Components and Hooks must be pure" — react.dev/reference/rules/components-and-hooks-must-be-pure
  • React: <StrictMode> — react.dev/reference/react/StrictMode
  • React: "Render and Commit" — react.dev/learn/render-and-commit
  • eslint-plugin-react-hooks: globals, purity, immutability qoidalari — react.dev/reference/eslint-plugin-react-hooks
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Pure komponentlar va render qoidasi: React nega StrictMode'da ikki marta chaqiradi — IlmHamroh