Mundarija (32)
- Bu darsda
- 1. Nega bu kerak?
- 2. State o'ringa bog'langan
- 2.1 Ikki nusxa — ikki xotira
- 2.2 O'rindan olib tashlansa — state yo'qoladi
- 3. Bir joy — bir state
- 3.1 Props o'zgarsa — state saqlanadi
- 3.2 Ternary tuzog'i
- 4. Tur o'zgarsa — butun pastki daraxt yangilanadi
- 4.1 Boshqa komponent o'sha o'rinda
- 4.2 O'ram o'zgarsa ham
- 4.3 Komponent ichida komponent e'lon qilmang
- 5. key bilan state'ni boshqarish
- 5.1 key faqat ro'yxat uchun emas
- 5.2 Ternary tuzog'ini key bilan yechish
- 5.3 Formani "tozalash" uchun key
- 5.4 Props o'zgarganda state'ni noldan boshlash
- 6. Ro'yxatdagi key va state
- 6.1 Indeks key state'ni chalkashtiradi
- 6.2 Barqaror id — to'g'ri key
- 7. Vazifalar: tahrirdagi matn nega yo'qolmaydi
- 7.1 key={vazifa.id} — fon yangilanishiga chidamli
- 7.2 Tur almashishi — ataylab reset
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): Saqlanadimi?
- 2-mashq (o'rta): Mehmon izohi
- 3-mashq (qiyin): Saralanadigan tahrir ro'yxati
- 4-mashq: Vazifalar tajribasi (commit yo'q)
- 10. Real ishda
- Xulosa
- Manbalar
State'ning saqlanishi va key bilan reset: daraxtdagi o'rin qoidasi
Qisqacha: React state'ni komponent funksiyasiga emas, UI daraxtidagi o'rniga bog'laydi. Bir xil turdagi komponent bir xil o'rinda chizilaversa — state saqlanadi (props boshqa bo'lsa ham). Komponent o'rindan olib tashlansa yoki o'sha o'rinda boshqa tur chizilsa — state yo'qoladi.
keyo'rinni nomlaydi:keyo'zgarsa, React uni yangi komponent deb oladi va state noldan boshlanadi. Shuning uchun komponentni boshqa komponent ichida e'lon qilmang va state'li ro'yxatda indeksnikeyqilmang.
Bu darsda
- State qachon saqlanishi va qachon yo'qolishini oldindan ayta olasiz.
- "Bir joy — bir state" qoidasini ternary misolida tushuntirasiz.
- Komponent turi yoki o'rami o'zgarganda nega state o'chishini bilasiz.
keybilan state'ni ataylab noldan boshlaysiz.- Komponent ichida komponent e'lon qilish va indeks
keytuzoqlarini taniysiz. vazifalarda tahrirdagi matn nega fon yangilanishida yo'qolmasligini tushuntira olasiz.
Oldin bilishingiz kerak: State'ni ko'tarish, Ro'yxatlarni render qilish va key, State I: useState.
1. Nega bu kerak?
Oldingi darsda state'ni "kimda saqlash" ni hal qildik. Bugun boshqa savol: React state'ni qachongacha eslab turadi?
Sardor «Bahor» ofitsianti uchun buyurtma paneli yozdi. Tepada stol tanlanadi (4-stol, 7-stol), pastda OrderPanel komponenti — "qo'shimcha non" soni va tugma. Ofitsiant 4-stolga uchta non yozdi, keyin 7-stolni tanladi. Ekranda 7-stol uchun ham "3 ta non" turibdi. Sardor hayron: "Axir OrderPanel ga yangi stol raqami berildi-ku!"
Boshqa kuni teskarisi bo'ldi. U panelni chiroyli ramkaga o'radi, ya'ni <div> ni <section> ga almashtirdi. Endi ramka yoqilganda yoki o'chirilganda son nolga tushib qolardi — stol hatto almashmagan bo'lsa ham.
Ikkala hodisa ham bitta qoidadan kelib chiqadi. Uni bilmasangiz, React "o'z boshiga" ish qilayotgandek tuyuladi. Bilsangiz — state'ni xohlagan paytda saqlaysiz yoki ataylab tozalaysiz.
Hayotiy o'xshatish: restoran zalidagi stollar. Ofitsiant buyurtmani mehmonga emas, stol raqamiga yozadi: "4-stol — 3 ta non". 4-stolga boshqa mehmon o'tirsa ham, daftarda yozuv turaveradi — ofitsiant stol raqamiga qaraydi. Yozuvni o'chirish uchun stolni "yangi" deb belgilash kerak. React'da "stol raqami" — komponentning daraxtdagi o'rni, "yangi deb belgilash" esa key.
2. State o'ringa bog'langan
2.1 Ikki nusxa — ikki xotira
Mehmonlar hisoblagichi (har stol uchun):
import { useState } from "react";
function Counter({ label }) {
const [count, setCount] = useState(0);
return (
<p>
{label}: {count}{" "}
<button onClick={() => setCount(count + 1)}>{label} +</button>
</p>
);
}
function App() {
return (
<div>
<Counter label="4-stol" />
<Counter label="7-stol" />
</div>
);
}Ekranda:
4-stol: 2 4-stol +
7-stol: 1 7-stol +Counter funksiyasi bitta, lekin xotira ikkita. React state'ni funksiyada emas, daraxtdagi o'rinda saqlaydi: "div ning 1-bolasi — Counter, count 2", "div ning 2-bolasi — Counter, count 1".
flowchart TD
A["App"] --> D["div"]
D --> C1["Counter (1-o'rin) — count: 2"]
D --> C2["Counter (2-o'rin) — count: 1"]Bu daraxtni React JSX'dan quradi. Komponent funksiyasi har renderda qaytadan chaqiriladi, lekin useState "men qaysi o'rindaman?" deb so'raydi va o'sha o'rinning xotirasini qaytaradi.
2.2 O'rindan olib tashlansa — state yo'qoladi
Ikkinchi hisoblagichni yashirib, qayta ko'rsatamiz:
import { useState } from "react";
function Counter({ label }) {
const [count, setCount] = useState(0);
return (
<p>
{label}: {count}{" "}
<button onClick={() => setCount(count + 1)}>{label} +</button>
</p>
);
}
function App() {
const [show, setShow] = useState(true);
return (
<div>
{show && <Counter label="7-stol" />}
<button onClick={() => setShow(false)}>Yashir</button>{" "}
<button onClick={() => setShow(true)}>Ko'rsat</button>
</div>
);
}Ekranda:
7-stol: 0 7-stol +
Yashir Ko'rsat| Qadam | O'rinda nima | count |
Ekranda |
|---|---|---|---|
| «7-stol +» | Counter |
1 | 7-stol: 1 |
| «Yashir» | false (hech narsa) |
— (o'chirildi) | — |
| «Ko'rsat» | yangi Counter |
0 | 7-stol: 0 |
Komponent daraxtdan olib tashlanganda React uning state'ini ham yo'q qiladi. Qayta paydo bo'lgan Counter — butunlay yangi, useState(0) dan boshlaydi. Bu display: none emas: komponentning o'zi va DOM elementlari ham olib tashlanadi.
Maslahat: Yashirilgan qismning state'i saqlanishi kerak bo'lsa, uch yo'l bor: state'ni otaga ko'tarish; komponentni o'chirmasdan CSS bilan yashirish (
hiddenatributi); yoki React 19.2 dan barqaror bo'lgan<Activity mode="hidden">komponenti — Activity darsida.
3. Bir joy — bir state
3.1 Props o'zgarsa — state saqlanadi
Sardorning birinchi muammosiga qaytamiz. Buyurtma paneli stol raqamini props'dan oladi:
import { useState } from "react";
function OrderPanel({ table }) {
const [bread, setBread] = useState(0);
return (
<p>
{table}-stol: {bread} ta non{" "}
<button onClick={() => setBread(bread + 1)}>Non +</button>
</p>
);
}
function App() {
const [table, setTable] = useState(4);
return (
<div>
<button onClick={() => setTable(4)}>4-stol</button>{" "}
<button onClick={() => setTable(7)}>7-stol</button>
<OrderPanel table={table} />
</div>
);
}Ekranda:
4-stol 7-stol
7-stol: 3 ta non Non +Stol raqami yangilandi, non soni — yo'q. React nuqtai nazaridan hech narsa o'zgarmagan: o'sha o'rinda o'sha tur (OrderPanel) turibdi. Yangi props — yangi matn, lekin xotira o'sha. Bu ko'p hollarda kerakli xulq: masalan, tanlangan rang o'zgarganda formadagi yozilgan matn yo'qolmasligi. Bu safar esa xato.
3.2 Ternary tuzog'i
Yana ham kutilmagan holat: ternary ikki har xil JSX'ni qaytaradi, lekin state baribir umumiy.
import { useState } from "react";
function Counter({ label }) {
const [count, setCount] = useState(0);
return (
<p>
{label}: {count}{" "}
<button onClick={() => setCount(count + 1)}>{label} +</button>
</p>
);
}
function App() {
const [isVip, setIsVip] = useState(true);
return (
<div>
{isVip ? <Counter label="VIP" /> : <Counter label="Oddiy" />}
<button onClick={() => setIsVip(!isVip)}>
{isVip ? "Oddiy zal" : "VIP zal"}
</button>
</div>
);
}Ekranda:
Oddiy: 2 Oddiy +
VIP zalVIP zalda ikki mehmon sanaldi, oddiy zalga o'tildi — u yerda ham 2. Kodda ikkita <Counter> yozilgan, lekin React ularni bitta deb ko'radi. Sabab — React JSX matniga emas, natijaga qaraydi:
isVip |
div ning 1-bolasi |
React xulosasi |
|---|---|---|
true |
Counter (label "VIP") |
— |
false |
Counter (label "Oddiy") |
o'sha o'rin, o'sha tur → state saqlanadi |
React uchun <Counter label="VIP" /> va <Counter label="Oddiy" /> — bir xil o'rindagi bir xil komponent, faqat props boshqa. Ternary'ning qaysi tarmog'idan kelgani unga ahamiyatsiz.
Tekshirib ko'ring:
{isVip && <Counter label="VIP" />}{!isVip && <Counter label="Oddiy" />}deb yozilsa, VIP'dan oddiyga o'tganda count saqlanadimi?
Javob
Yo'q, nolga tushadi. Endi div da ikki o'rin bor: 1-o'rinda VIP hisoblagich yoki false, 2-o'rinda false yoki oddiy hisoblagich. false ham o'rin egallaydi (chizilmasa ham). VIP o'chganda 1-o'rindagi Counter yo'qoladi, oddiy esa 2-o'rinda noldan paydo bo'ladi. Bu — key siz ikki state'ni ajratish usuli; key bilan usul — pastda.
4. Tur o'zgarsa — butun pastki daraxt yangilanadi
4.1 Boshqa komponent o'sha o'rinda
O'rin bir xil, lekin tur boshqa bo'lsa, React eski komponentni va uning ichidagi hamma narsani o'chiradi:
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<p>
Mehmonlar: {count}{" "}
<button onClick={() => setCount(count + 1)}>+1</button>
</p>
);
}
function App() {
const [isBreak, setIsBreak] = useState(false);
return (
<div>
{isBreak ? <p>Tanaffus, 15 daqiqa</p> : <Counter />}
<button onClick={() => setIsBreak(!isBreak)}>
{isBreak ? "Qaytish" : "Tanaffus"}
</button>
</div>
);
}Ekranda:
Mehmonlar: 0 +1
TanaffusTanaffus paytida o'rinda <p> turdi, Counter o'chirildi. «Qaytish» bosilganda — yangi Counter, hisob 0.
4.2 O'ram o'zgarsa ham
Bu qoida faqat komponentning o'ziga emas, uning ota-bobolariga ham tegishli. Sardorning ikkinchi muammosi — o'ramni almashtirish:
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<p>
Mehmonlar: {count}{" "}
<button onClick={() => setCount(count + 1)}>Mehmon +</button>
</p>
);
}
function App() {
const [framed, setFramed] = useState(false);
const toggle = (
<button onClick={() => setFramed(!framed)}>Ramka</button>
);
if (framed) {
return (
<section className="ramka">
<Counter />
{toggle}
</section>
);
}
return (
<div>
<Counter />
{toggle}
</div>
);
}Ekranda:
Mehmonlar: 0 Mehmon +
RamkaCounter o'zgarmadi, lekin uning otasi div dan section ga aylandi. React ildizdan boshlab solishtiradi: "1-o'rinda avval div edi, endi section — boshqa tur". Butun div daraxti o'chiriladi, section daraxti noldan quriladi. Qoidani eslab qoling: renderlar orasida daraxt "skeleti" bir xil qolsin. Ramka kerak bo'lsa, tegni emas, className ni almashtiring: <div className={framed ? "ramka" : ""}>.
4.3 Komponent ichida komponent e'lon qilmang
Bu qoidaning eng yashirin ko'rinishi:
import { useState } from "react";
function App() {
const [outer, setOuter] = useState(0);
function Inner() { // ❌ har renderda YANGI funksiya
const [inner, setInner] = useState(0);
return (
<p>
Ichki: {inner}{" "}
<button onClick={() => setInner(inner + 1)}>Ichki +</button>
</p>
);
}
return (
<div>
<Inner />
<p>
Tashqi: {outer}{" "}
<button onClick={() => setOuter(outer + 1)}>Tashqi +</button>
</p>
</div>
);
}Ekranda:
Ichki: 0 Ichki +
Tashqi: 1 Tashqi +Ichki hisob 2 edi — tashqi tugma bosilgach 0 ga tushdi. App har chaqirilganda function Inner yangi funksiya obyekti sifatida yaratiladi. React turni solishtirganda Object.is ishlatadi: eski Inner va yangi Inner — ikki xil funksiya, demak ikki xil tur. Natija — "tur o'zgardi, state'ni o'chir".
Tuzatish: komponentni har doim fayl darajasida (modulning yuqori qismida) e'lon qiling. Inner ga App dagi qiymat kerak bo'lsa — props bilan bering.
Diqqat: Bu xato faqat state'ni emas, fokus va input ichidagi matnni ham yo'qotadi: har harfda maydon qayta yaratiladi va fokus "uchib ketadi". "Har harf yozganda input fokusni yo'qotyapti" — React forumlaridagi eng ko'p so'raladigan savollardan biri, sababi deyarli har doim shu.
5. key bilan state'ni boshqarish
5.1 key faqat ro'yxat uchun emas
Ro'yxatlar va key darsida key ni .map() dagi elementlar uchun ishlatdik. Aslida key istalgan komponentga beriladi. U o'rinni nomlaydi: React endi "ota ichidagi 1-o'rin" deb emas, "ota ichidagi key=7 li o'rin" deb qaraydi. key o'zgarsa — boshqa o'rin, demak yangi komponent va yangi state.
Sardorning non muammosi bir so'z bilan tuzaladi:
import { useState } from "react";
function OrderPanel({ table }) {
const [bread, setBread] = useState(0);
return (
<p>
{table}-stol: {bread} ta non{" "}
<button onClick={() => setBread(bread + 1)}>Non +</button>
</p>
);
}
function App() {
const [table, setTable] = useState(4);
return (
<div>
<button onClick={() => setTable(4)}>4-stol</button>{" "}
<button onClick={() => setTable(7)}>7-stol</button>
<OrderPanel key={table} table={table} />
</div>
);
}Ekranda:
4-stol 7-stol
7-stol: 0 ta non Non +key={table} — "har stol uchun alohida panel". 4-stoldan 7-stolga o'tganda key 4 dan 7 ga o'zgaradi. React eski panelni o'chiradi, yangisini bread = 0 bilan yaratadi.
Diqqat: 4-stolga qaytsangiz, uchta non ham qaytmaydi. React eski key=4 panelini o'chirib yuborgan, u hech qayerda saqlanmaydi. Har stolning buyurtmasini eslab qolish kerak bo'lsa, state'ni otaga ko'taring: const [orders, setOrders] = useState({ 4: 3, 7: 0 }) — State strukturasi darsidagi tekis obyekt.
5.2 Ternary tuzog'ini key bilan yechish
VIP va oddiy zal hisoblagichlari alohida bo'lishi kerak bo'lsa:
{isVip ? (
<Counter key="vip" label="VIP" />
) : (
<Counter key="oddiy" label="Oddiy" />
)}Endi o'rin bir xil bo'lsa ham, nomlar boshqa — har zalga o'tishda hisob noldan boshlanadi.
5.3 Formani "tozalash" uchun key
Buyurtma qabul qilingach, butun formani boshlang'ich holatga qaytarish kerak. Har state'ni birma-bir nolga tushirish o'rniga, formaga key berib, uni oshirib qo'yish mumkin:
import { useState } from "react";
function OrderForm({ onSend }) {
const [bread, setBread] = useState(0);
const [tea, setTea] = useState(1);
return (
<p>
Non: {bread}, choy: {tea}{" "}
<button onClick={() => setBread(bread + 1)}>Non +</button>{" "}
<button onClick={() => setTea(tea + 1)}>Choy +</button>{" "}
<button onClick={() => onSend(bread, tea)}>Yuborish</button>
</p>
);
}
function App() {
const [version, setVersion] = useState(0);
const [last, setLast] = useState("—");
function handleSend(bread, tea) {
setLast(`${bread} non, ${tea} choy`);
setVersion(version + 1); // yangi key — yangi forma
}
return (
<div>
<OrderForm key={version} onSend={handleSend} />
<p>Oxirgi buyurtma: {last}</p>
</div>
);
}Ekranda:
Non: 0, choy: 1 Non + Choy + Yuborish
Oxirgi buyurtma: 2 non, 1 choyOrderForm ichida nechta state bo'lishidan qat'i nazar, hammasi boshlang'ich qiymatga qaytdi. Ertaga formaga yangi maydon qo'shilsa ham, tozalash kodi o'zgarmaydi.
Tekshirib ko'ring:
OrderFormgakey={version}o'rnigakey="forma"(doimiy satr) berilsa, «Yuborish» dan keyin non soni nolga tushadimi?
Javob
Yo'q. Doimiy key — har renderda bir xil nom, demak o'sha o'rin va o'sha komponent: state saqlanadi. key faqat o'zgarganda reset qiladi. Shuning uchun version har yuborishda oshiriladi — yangi qiymat, yangi komponent.
5.4 Props o'zgarganda state'ni noldan boshlash
State strukturasi darsida useState(props.x) tuzog'ini ko'rgan edik: state props'ning faqat birinchi qiymatini oladi. Ba'zan aynan shu kerak — lekin props butunlay boshqa narsaga o'tganda (boshqa stol, boshqa mehmon) state ham yangidan boshlanishi kerak. Buning eng toza yo'li — key:
<EditGuest key={guest.id} initialName={guest.name} />Mehmon almashsa — key almashadi, EditGuest yangidan yaratiladi va useState(initialName) yangi ismni oladi. Effekt bilan "props o'zgarganda state'ni yangila" yozish — keng tarqalgan, lekin ortiqcha va sekin yo'l (Sizga effekt kerak emas).
6. Ro'yxatdagi key va state
6.1 Indeks key state'ni chalkashtiradi
Ro'yxatlar va key darsida indeksni key qilish xavfli ekanini aytgan edik. Endi aynan qayerda xavfli ekanini ko'ramiz: qatorlarning o'z state'i bo'lganda.
import { useState } from "react";
function Row({ name, onRemove }) {
const [qty, setQty] = useState(0);
return (
<li>
{name}: {qty}{" "}
<button onClick={() => setQty(qty + 1)}>{name} +</button>{" "}
<button onClick={onRemove}>{name} o'chirish</button>
</li>
);
}
function App() {
const [dishes, setDishes] = useState(["Osh", "Manti"]);
return (
<ul>
{dishes.map((d, i) => (
<Row // ❌ key={i}
key={i}
name={d}
onRemove={() => setDishes(dishes.filter((x) => x !== d))}
/>
))}
</ul>
);
}Ekranda:
Manti: 2 Manti + Manti o'chirishOshga 2 porsiya yozildi va osh o'chirildi. Endi manti 2 porsiya bo'lib qoldi! Nima bo'ldi:
key=0 o'rni |
key=1 o'rni |
|
|---|---|---|
| oldin | Osh, qty 2 | Manti, qty 0 |
| osh o'chgach | Manti, qty 2 | — (o'chirildi) |
React key=0 ni ko'rib, "bu o'sha qator, faqat name props'i o'zgardi" deb o'yladi va state'ni saqladi. key=1 esa yo'qoldi — mantining haqiqiy state'i (0) u bilan birga o'chirildi.
6.2 Barqaror id — to'g'ri key
import { useState } from "react";
function Row({ name, onRemove }) {
const [qty, setQty] = useState(0);
return (
<li>
{name}: {qty}{" "}
<button onClick={() => setQty(qty + 1)}>{name} +</button>{" "}
<button onClick={onRemove}>{name} o'chirish</button>
</li>
);
}
function App() {
const [dishes, setDishes] = useState([
{ id: 1, name: "Osh" },
{ id: 2, name: "Manti" },
]);
return (
<ul>
{dishes.map((d) => (
<Row
key={d.id}
name={d.name}
onRemove={() =>
setDishes(dishes.filter((x) => x.id !== d.id))
}
/>
))}
</ul>
);
}Ekranda:
Manti: 0 Manti + Manti o'chirishkey={d.id} — kalit ma'lumotning o'ziga bog'langan. Osh o'chganda key=1 o'rni yo'qoladi, key=2 (manti) esa o'z state'i bilan qoladi. Saralash, filtrlash yoki boshiga qo'shishda ham shunday: React qatorlarni kalit bo'yicha ko'chiradi, qayta yaratmaydi.
Qoida: qatorlarda state, fokus yoki input bo'lsa — kalit faqat barqaror id. Indeks faqat ro'yxat hech qachon o'zgarmasa yoki qatorlar state'siz bo'lsa (oldingi darsdagi savat mashqi kabi) qabul qilinadi. Renderda Math.random() yoki crypto.randomUUID() bilan kalit yasash esa eng yomoni: har renderda hamma qator yangi, hamma state o'chadi.
7. Vazifalar: tahrirdagi matn nega yo'qolmaydi
Bu darsda vazifalar kodi o'zgarmaydi — uning ichida bugungi qoidalar allaqachon ishlayapti. Ularni o'qib chiqamiz.
7.1 key={vazifa.id} — fon yangilanishiga chidamli
VazifaRoyxati.tsx (kanondan):
// key — vazifa id: barqaror va takrorlanmaydi. Tartib o'zgarsa
// (saralash, bajarilgan pastga tushdi) React <li> ni yangidan
// yasamaydi, joyini almashtiradi — fokus va yozilgan
// matn saqlanadi
return vazifalar.map((vazifa) => (
<VazifaQatori
key={vazifa.id}
vazifa={vazifa}
sorov={sorov}
tahrirda={vazifa.id === tahrirId}
amallar={amallar}
/>
));Malika vazifani tahrirlayapti. Shu payt boshqa tabda yangi vazifa qo'shildi yoki serverdan yangilangan ro'yxat keldi. App qayta chiziladi, ro'yxat tartibi o'zgarishi mumkin. Lekin tahrirdagi qatorning key i o'sha — React uni ko'chiradi — <input> elementi, undagi yozilayotgan matn va fokus joyida qoladi.
v6 (vanilla) da har chizishda qatorlar replaceChildren bilan qayta yasalardi. Shuning uchun render.ts da "qoralamani qo'lda tiklash" kodi bor edi: yozilgan matnni chizishdan oldin eslab, keyin qaytarib qo'yish. React'ga o'tilgach u kerak bo'lmay qoldi. render.tsx dagi izoh shuni aytadi (izoh qatorlari telefon uchun qayta bo'lindi):
// Fon yangilanishi (server, boshqa tab, qaytarish). React qatorni
// key bo'yicha SAQLAYDI: fokus va tahrirdagi matn o'z-o'zidan
// joyida (v6 da qatorlar qayta yasalardi — ikkalasini qo'lda
// tiklardik). Faqat fokusdagi qator yo'qolgan bo'lsa (boshqa tab
// o'chirgan) — qo'shni yoki sarlavha7.2 Tur almashishi — ataylab reset
VazifaQatori.tsx da:
if (tahrirda) {
return <TahrirQatori vazifa={vazifa} {...amallar} />;
}
return <OddiyQator vazifa={vazifa} sorov={sorov} {...amallar} />;Bir o'rinda ikki har xil tur. Tahrir boshlanganda OddiyQator o'chadi, TahrirQatori noldan yaratiladi. Uning ichidagi maydon hozircha shunday (kanondan):
{/* defaultValue — boshlang'ich qiymat, keyin maydon o'ziniki
(uncontrolled). Fon yangilanganda React shu <input> ni
QAYTA YARATMAYDI — yozilayotgan matn joyida qoladi */}
<input
id={TAHRIR_MAYDONI_ID}
defaultValue={vazifa.matn}defaultValue — boshlang'ich matn, u faqat element yaratilganda yoziladi (useState(…) ning boshlang'ich qiymatiga o'xshaydi; to'liq — Formalar II darsida). Tur almashgani uchun har tahrir yangi TahrirQatori va yangi <input> — demak har safar vazifaning joriy matni bilan boshlanadi. "Bekor qilish" bosilsa — TahrirQatori o'chadi va yozilgan qoralama ham. Keyingi darsda bu matn React state'iga (useState(vazifa.matn)) ko'chadi — qoida o'zgarmaydi. Keyingi tahrir yana toza boshlanadi. Bugungi darsning ikki qoidasi bitta qatorda ishlayapti: tur almashsa — reset, key o'zgarmasa — saqlanadi.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| boshqa elementga o'tilsa ham eski state qoladi | o'sha o'rin, o'sha tur | key={element.id} |
| ternary'ning ikki tarmog'i state'ni "ulashadi" | bir o'rin, bir tur | har tarmoqqa boshqa key |
| teg almashganda state nolga tushadi | o'ram turi o'zgardi | tegni emas, className ni almashtiring |
| har harfda input fokusni yo'qotadi | komponent boshqa komponent ichida e'lon qilingan | e'lonni fayl darajasiga chiqaring |
| o'chirishdan keyin state qo'shni qatorga "ko'chadi" | key={index} |
barqaror id |
| har renderda hamma qator noldan | key={Math.random()} |
ma'lumotdagi id |
9. Mashqlar
Mashqlar kurs/mashqlar/17/17-state-saqlanishi/ da.
1-mashq (oson): Saqlanadimi?
Har holatda Counter ichidagi state (count = 3) keyingi renderda saqlanadimi?
<Counter color="red" />→<Counter color="blue" />, o'sha o'rinda:{show && <Counter />}dashowtrue→false→true:<div><Counter /></div>→<article><Counter /></article>:<Counter key="a" />→<Counter key="b" />:
Yechim
- Ha — o'rin va tur bir xil, faqat props o'zgardi.
- Yo'q —
falsepaytida komponent daraxtdan olib tashlandi, state ham yo'qoldi. - Yo'q — o'ram turi o'zgardi, butun pastki daraxt qayta quriladi.
- Yo'q —
keyboshqa, React uni yangi komponent deb oladi.
2-mashq (o'rta): Mehmon izohi
GuestNote komponentida mehmonning "yoqdi" (likes) hisobi bor. Tepada uchta mehmon tugmasi: Ali, Malika, Bobur. Hozir mehmon almashganda hisob eskisidan qoladi. Ikki narsani qiling: (a) mehmon almashsa, hisob noldan boshlansin; (b) pastda «Yangi tashrif» tugmasi bo'lsin — bosilsa, o'sha mehmonning hisobi ham noldan boshlansin. Ishora: key ga ikki qiymatni birlashtirib berish mumkin — key={`${guest}-${visit}`}.
Yechim
import { useState } from "react";
function GuestNote({ guest }) {
const [likes, setLikes] = useState(0);
return (
<p>
{guest}: {likes} ta yoqdi{" "}
<button onClick={() => setLikes(likes + 1)}>+1</button>
</p>
);
}
function App() {
const [guest, setGuest] = useState("Ali");
const [visit, setVisit] = useState(0);
return (
<div>
{["Ali", "Malika", "Bobur"].map((g) => (
<button key={g} onClick={() => setGuest(g)}>
{g}
</button>
))}
<GuestNote key={`${guest}-${visit}`} guest={guest} />
<button onClick={() => setVisit(visit + 1)}>
Yangi tashrif
</button>
</div>
);
}Ekranda:
AliMalikaBobur
Malika: 0 ta yoqdi +1
Yangi tashrifAli'ga 1, keyin Malika'ga o'tildi (yangi key — 0), unga 1 qo'shildi, «Yangi tashrif» — visit oshdi, key yana o'zgardi, hisob 0.
3-mashq (qiyin): Saralanadigan tahrir ro'yxati
vazifalar dagi naqshni kichik misolda takrorlang. Ro'yxatda taomlar: { id, name }. Har qatorda «Tahrir» tugmasi; tahrirdagi qator EditRow — uning ichida useState(dish.name) va «Belgi qo'sh» tugmasi (nom oxiriga ! qo'shadi, ya'ni "yozilgan qoralama"ni almashtiradi). Ro'yxat ustida «Alifbo» tugmasi — nomlar bo'yicha saralaydi (toSorted va localeCompare — Immutable yangilash). Talab: tahrir paytida saralansa ham, qoralama (!) yo'qolmasin. Tahrirdagi qator id bilan saqlansin (editId). Sinov: "Osh", "Manti", "Lag'mon" — Osh'ni tahrirlang, «Belgi qo'sh», keyin «Alifbo».
Yechim
import { useState } from "react";
function EditRow({ dish }) {
const [draft, setDraft] = useState(dish.name);
return (
<li>
Qoralama: {draft}{" "}
<button onClick={() => setDraft(draft + "!")}>
Belgi qo'sh
</button>
</li>
);
}
function ViewRow({ dish, onEdit }) {
return (
<li>
{dish.name}{" "}
<button onClick={onEdit}>{dish.name} tahrir</button>
</li>
);
}
function App() {
const [dishes, setDishes] = useState([
{ id: 1, name: "Osh" },
{ id: 2, name: "Manti" },
{ id: 3, name: "Lag'mon" },
]);
const [editId, setEditId] = useState(null);
function sortByName() {
setDishes(
dishes.toSorted((a, b) => a.name.localeCompare(b.name)),
);
}
return (
<div>
<button onClick={sortByName}>Alifbo</button>
<ul>
{dishes.map((d) =>
d.id === editId ? (
<EditRow key={d.id} dish={d} />
) : (
<ViewRow
key={d.id}
dish={d}
onEdit={() => setEditId(d.id)}
/>
),
)}
</ul>
</div>
);
}Ekranda:
Alifbo
Lag'mon Lag'mon tahrir
Manti Manti tahrir
Qoralama: Osh! Belgi qo'shOsh alifbo bo'yicha oxiriga tushdi, lekin key={1} o'zgarmadi — React EditRow ni ko'chirdi, draft ("Osh!") saqlandi. key={index} bilan sinab ko'ring: saralashdan keyin 3-o'rinda EditRow turadi, lekin u yangi — qoralama yo'qoladi.
4-mashq: Vazifalar tajribasi (commit yo'q)
vazifalar ni npm run dev bilan oching. Bitta vazifani tahrirlashni boshlang va matnga bir necha harf qo'shing. Ikkinchi tabda xuddi shu sahifani ochib, boshqa vazifani bajarilgan deb belgilang. Birinchi tabga qayting: tahrirdagi matn va fokus joyidami? Keyin VazifaRoyxati.tsx da vaqtincha key={vazifa.id} ni key={indeks} ga almashtiring (map((vazifa, indeks) => …)), tajribani tahrirdagi qatordan tepadagi vazifani o'chirib takrorlang va farqni yozing. Oxirida o'zgarishni qaytaring: git checkout -- src/.
Yechim
key={vazifa.id} bilan: boshqa tabdagi o'zgarish App ni qayta chizadi, tahrirdagi qatorning kaliti o'sha — matn va fokus joyida. Indeks bilan: tepadagi qator o'chganda tahrirdagi vazifa bir o'rin yuqoriga siljiydi va boshqa kalitni oladi. Natija 3-mashqdagi key={index} tajribasi bilan bir xil bo'lishi kerak. Tajribadan keyin git status toza bo'lsin — bu o'zgarish commit qilinmaydi.
10. Real ishda
- Profil yoki chat almashtirish — "boshqa foydalanuvchiga o'tganda eski xabar qoralamasi qoldi" — klassik xato, davosi
key={userId}. React hujjatining asosiy misoli aynan shu. - Formani tozalash —
keybilan qayta yaratish ko'p ishlatiladi, ayniqsa forma ichida ko'p maydon va ichki komponentlar bo'lsa. - Fokus yo'qolishi — kod ko'rigida "komponent render ichida e'lon qilingan" — tez-tez topiladigan xato. Bu xulqning ichki mexanizmi (reconciliation, Fiber) — Reconciliation darsida.
- Intervyu savollari: "React state qayerda saqlanadi?", "
keyro'yxatdan tashqarida nima uchun ishlatiladi?", "Nega komponentni boshqa komponent ichida e'lon qilmaslik kerak?", "Indekskeyqachon xatoga olib keladi?".
Xulosa
- State komponent funksiyasiga emas, UI daraxtidagi o'ringa bog'langan.
- O'sha o'rin + o'sha tur = state saqlanadi, props o'zgarsa ham; ternary'ning ikki tarmog'i ham.
- Komponent olib tashlansa yoki tur (yoki o'ram turi) o'zgarsa — butun pastki daraxt state'i yo'qoladi.
- Komponentni komponent ichida e'lon qilmang: har renderda yangi tur.
keyo'rinni nomlaydi: o'zgarsa — state noldan; bu formani tozalash va "boshqa element" ga o'tish uchun.- Qatorlarda state bo'lsa — kalit faqat barqaror id;
vazifalardagi tahrir matni shu tufayli saqlanadi.
Keyingi dars: Formalar I: controlled inputlar — input qiymatini state'dan boshqarish: matn, textarea, select, checkbox va radio.
Manbalar
- React: "Preserving and Resetting State" — react.dev/learn/preserving-and-resetting-state
- React: "Rendering Lists" (kalit qoidalari) — react.dev/learn/rendering-lists
- React:
<Activity>— react.dev/reference/react/Activity - React blog: "React 19.2" (2025-10-01,
<Activity>) — react.dev/blog
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!