Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Xabarni o'qish tartibi
- 2.1 Uch savol
- 2.2 Ogohlantirish — ham xato
- 3. Render paytidagi xatolar
- 3.1 Too many re-renders
- 3.2 Cannot update a component while rendering a different component
- 3.3 Objects are not valid as a React child
- 3.4 Hook tartibi buzilsa
- 4. Effekt xatolari
- 4.1 Cheksiz effekt sikli
- 4.2 Eskirgan closure (stale closure)
- 5. State bilan ishlashdagi xatolar
- 5.1 Mutatsiya — ekran yangilanmaydi
- 5.2 Controlled va uncontrolled almashishi
- 6. Ro'yxat va key
- 6.1 Kalitsiz va takror kalit
- 6.2 Indeks kalit — jim xato
- 7. Katalog: bir jadvalda
- 8. Ko'p uchraydigan xatolar: davoning o'zi xato bo'lsa
- 9. Mashqlar
- 1-mashq (oson): xabardan sababga
- 2-mashq (o'rta): navbat taymeri
- 3-mashq (qiyin): uch xatoli savat
- 10. Real ishda
- Xulosa
- Manbalar
React xatolari katalogi: eng ko'p uchraydigan xabarlar, sabablari va davosi
Qisqacha: React xatolarining aksariyati sakkiz-o'nta oilaga bo'linadi. Ular uch joyda tug'iladi: render paytida (renderda
setState, obyektni JSX'ga berish, hook tartibi), effektda (bog'liqliksizsetState— cheksiz sikl, eskirgan closure) va state bilan ishlashda (mutatsiya,key,undefineddan qiymatga sakrash). Har xabarni shu uch savol bilan o'qing: xato yoki ogohlantirishmi, qaysi bosqichda, qaysi komponentda. Bu dars — katalog: xabarning asl matni, tarjimasi, ildiz sababi va davosi.
Bu darsda
- React xabarini "xato yoki ogohlantirish, qaysi bosqich, qaysi komponent" tartibida o'qiysiz.
Too many re-renders,Cannot update a component while rendering,Objects are not valid as a React childning ildiz sababini topasiz.- Cheksiz effekt siklini va eskirgan closure'ni (stale closure) ko'rib taniysiz va tuzatasiz.
- Mutatsiya,
keyva controlled/uncontrolled almashishi qanday "jim" xatolar berishini tushuntira olasiz. - Xatoni yashiradigan "davolar"dan (ESLint'ni o'chirish,
StrictModeni olib tashlash) qochasiz.
Oldin bilishingiz kerak: React ilovani debug qilish, Sizga effekt kerak emas, State II: snapshot, batching va updater funksiya.
1. Nega bu kerak?
Oldingi darsda og'ir ishni UI'dan ajratdik. Endi kod ko'payib, «Bahor» ilovasiga yangi odam keldi. Sardor (stajyor) birinchi haftada uch marta qotib qoldi. Birinchi kuni sahifa oq bo'lib qoldi va konsolda Too many re-renders turardi. Ikkinchi kuni taymer 1 da to'xtab qoldi — hech qanday xabarsiz. Uchinchi kuni ro'yxatdan taom o'chirildi, lekin porsiya soni qo'shni taomga "ko'chib" o'tdi.
Uchala holatda ham Sardor xatoni uzoq qidirdi. Vaholanki bu xatolar React dasturchilarining hammasi qiladigan xatolar — ularning ro'yxati qisqa. Jasur aka ularni ko'zi bilan tanib oladi: "Bu — renderda setState", "bu — eskirgan closure". U aqlli bo'lgani uchun emas, shunchaki bu xatolarni ko'p ko'rgani uchun shunday.
Hayotiy o'xshatish: tajribali usta mashina ovozidan "bu — rezina", "bu — podshipnik" deydi. Uning boshida ovozlar katalogi bor. Bu dars sizga shunday katalog beradi. Xatolarning o'zi React ilovani debug qilish darsidagi usullar bilan topiladi. Bu yerda esa ularning "yuzi" — xabar matni va belgisi.
2. Xabarni o'qish tartibi
2.1 Uch savol
Har xabarni ko'rganda uchta savol bering:
- Xatomi yoki ogohlantirishmi?
Uncaught Error: …— xato: komponent chizilmaydi, saytdagi natija oynasida «Komponentni chizishda xato» qutisi chiqadi. Oddiy matn (console.error) — ogohlantirish: ekran ishlayveradi, lekin nimadir noto'g'ri. - Qaysi bosqichda? Render (komponent funksiyasi chaqirilganda), commit va effekt (ekranga yozilgandan keyin) yoki hodisa (tugma bosilganda). Xabarning o'zi ko'pincha aytadi:
while rendering,inside useEffect. - Qaysi komponentda? Xabardagi
`App`,`Child`nomlari,Check the render method of …qatori va component stack.
Bu savollar sizni katalogning to'g'ri qatoriga olib boradi:
flowchart TD
X[Konsolda xabar] --> T{Uncaught Error?}
T -->|ha| R{Render paytida?}
T -->|yo'q| O[Ogohlantirish]
R -->|ha| R1[Too many re-renders<br/>Objects are not valid<br/>hook tartibi]
R -->|effektda| E1[Maximum update depth]
O --> O1[key, controlled,<br/>Cannot update]
X2[Xabar yo'q, ekran noto'g'ri] --> J[Jim xatolar:<br/>stale closure, mutatsiya,<br/>indeks key]Diagrammaning pastki qatoriga e'tibor bering. Eng qiyin xatolar umuman xabar bermaydi — ekran shunchaki noto'g'ri. Ularni faqat belgisidan tanish mumkin. Shuning uchun katalogda har xatoning belgisi ham yozilgan.
2.2 Ogohlantirish — ham xato
React ogohlantirishi development build'da chiqadi, production'da esa jim bo'ladi. Ko'p odam uni e'tiborsiz qoldiradi: "ishlayapti-ku". Lekin har ogohlantirish — ertangi xato. key ogohlantirishi bugun hech narsa buzmaydi, ertaga esa state qo'shni qatorga ko'chadi. Qoida: development'da konsol toza bo'lsin. vazifalar kanonining e2e tekshiruvi ham shunday ishlaydi: konsoldagi har console.error — tekshiruv muvaffaqiyatsiz.
Tekshirib ko'ring: Sahifa ishlayapti, lekin konsolda qizil
Each child in a list should have a unique "key" prop.turibdi. Bu xatomi yoki ogohlantirishmi? Production'da foydalanuvchi uni ko'radimi?
Javob
Ogohlantirish: Uncaught yo'q, ekran chizilgan. Production build'da React bu tekshiruvni umuman qilmaydi — foydalanuvchi xabarni ko'rmaydi. Lekin muammoning o'zi (kalitsiz ro'yxat) production'da ham qoladi: tartib o'zgarganda state noto'g'ri elementga yopishishi mumkin. Shuning uchun ogohlantirish ham tuzatiladi.
3. Render paytidagi xatolar
Render — React komponent funksiyangizni chaqirib, JSX olayotgan payt (Pure komponentlar va render qoidasi). Bu payt sof bo'lishi kerak: hisoblang va qaytaring, boshqa hech narsa qilmang. Bu bo'limdagi xatolarning hammasi shu qoidaning buzilishi.
3.1 Too many re-renders
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
setCount(count + 1); // ❌ render ichida
return <p>Buyurtmalar: {count}</p>;
}Konsolda:
Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop."Juda ko'p qayta render. React cheksiz siklning oldini olish uchun renderlar sonini cheklaydi." Zanjir: render → setCount → yangi render rejalashtirildi → yana render → yana setCount… React buni sanaydi va 25 ta ketma-ket renderdan keyin to'xtatadi.
Ikkinchi, ko'proq uchraydigan sababi bitta qavsda:
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
return (
<button onClick={setCount(count + 1)}>
Buyurtma: {count}
</button>
);
}Konsolda:
Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.onClick={setCount(count + 1)} — funksiyani berish emas, renderda chaqirish. onClick ga setCount qaytargan qiymat (undefined) tushadi, setCount esa har renderda ishlaydi (Hodisalarni boshqarish). Davosi — o'q funksiya:
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Buyurtma: {count}
</button>
);
}Ekranda:
Buyurtma: 2Birinchi variantning davosi esa boshqa: renderda setState kerak bo'lgan joyda odatda hosilaviy qiymat kerak edi. count dan hisoblanadigan narsa state bo'lmasin — renderda oddiy const bo'lsin (Sizga effekt kerak emas).
3.2 Cannot update a component while rendering a different component
Bola komponent render paytida otaning setter'ini chaqirsa:
import { useState } from "react";
function Total({ items, onTotal }) {
const sum = items.reduce((s, d) => s + d.price, 0);
onTotal(sum); // ❌ render paytida otani yangilaydi
return <p>Taomlar: {items.length} ta</p>;
}
function App() {
const [total, setTotal] = useState(0);
const items = [{ price: 35000 }, { price: 5000 }];
return (
<div>
<Total items={items} onTotal={setTotal} />
<p>Jami: {total} so'm</p>
</div>
);
}Konsolda:
Cannot update a component (`App`) while rendering a different component (`Total`). To locate the bad setState() call inside `Total`, follow the stack trace as described in https://react.dev/link/setstate-in-renderEkranda:
Taomlar: 2 ta
Jami: 40000 so'm"Total komponenti chizilayotganda boshqa komponentni (App) yangilab bo'lmaydi. Total ichidagi noto'g'ri setState() chaqiruvini topish uchun stack trace'ga qarang." Bu — ogohlantirish: ekran to'g'ri ko'rinadi. Lekin App bir renderda ikki marta chizildi va React render tartibiga ishonch yo'qoldi. Xabar ikkala ismni aniq aytadi: kim yangilandi (App) va kim yangiladi (Total).
Davosi — ma'lumotni yuqoriga "jo'natmaslik", balki yuqorida hisoblash. Jami summani items turgan joyda — App da — hisoblang:
function Total({ items }) {
return <p>Taomlar: {items.length} ta</p>;
}
function App() {
const items = [{ price: 35000 }, { price: 5000 }];
const total = items.reduce((s, d) => s + d.price, 0); // ✅
return (
<div>
<Total items={items} />
<p>Jami: {total} so'm</p>
</div>
);
}Ekranda:
Taomlar: 2 ta
Jami: 40000 so'mtotal state emas — hosilaviy qiymat. Bitta render, ogohlantirish yo'q. Agar ota haqiqatan hodisa haqida bilishi kerak bo'lsa ("buyurtma tasdiqlandi"), uni hodisa ishlovchisida chaqiring, renderda emas (State'ni ko'tarish).
3.3 Objects are not valid as a React child
function App() {
const dish = { name: "Osh", price: 35000 };
return <p>{dish}</p>;
}Konsolda:
Uncaught Error: Objects are not valid as a React child (found: object with keys {name, price}). If you meant to render a collection of children, use an array instead."Obyekt React bolasi bo'la olmaydi (topildi: name, price kalitli obyekt)." Bu xatoni JSX II darsida ko'rgansiz. Real ishda u ko'pincha serverdan kelgan ma'lumotda chiqadi: {order.customer} deb yozasiz, customer esa satr emas, { id, name } obyekti. Xabardagi kalitlar ro'yxati — eng yaxshi ishora: {id, name} ni ko'rsangiz, .name ni unutgansiz. Date obyekti ham shu xatoni beradi.
Yaqin qarindoshi — funksiya:
function App() {
const greet = () => "Xush kelibsiz!";
return <p>{greet}</p>;
}Konsolda:
Functions are not valid as a React child. This may happen if you return greet instead of <greet /> from render. Or maybe you meant to call this function rather than return it.
<p>{greet}</p>Bu — ogohlantirish, ekran esa bo'sh <p>. Xabar ikki taxmin beradi: komponent sifatida <Greet /> yozmoqchi edingiz yoki funksiyani chaqirmoqchi edingiz — {greet()}.
3.4 Hook tartibi buzilsa
import { useState } from "react";
function App() {
const [vip, setVip] = useState(false);
if (vip) {
const [percent] = useState(10); // ❌ shart ichida hook
}
return <button onClick={() => setVip(true)}>Chegirma</button>;
}Konsolda:
React has detected a change in the order of Hooks called by App. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://react.dev/link/rules-of-hooks
Previous render Next render
------------------------------------------------------
1. useState useState
2. undefined useState
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Uncaught Error: Rendered more hooks than during the previous render."Oldingi renderdagidan ko'proq hook chaqirildi." React hooklarni nomi bilan emas, tartib raqami bilan eslab qoladi: birinchi useState, ikkinchi useState… (Hooklar qoidalari). Birinchi renderda bitta hook bor edi, bosilgandan keyin — ikkita. Ro'yxat mos kelmay qoldi. Davosi — hookni doim yuqori darajada chaqirish, shartni esa qiymatga qo'yish: const [percent] = useState(10); va keyin vip ? percent : 0. ESLint'ning react-hooks/rules-of-hooks qoidasi buni kod yozayotganda ushlaydi — u vazifalar da 17-qismdan beri yoqilgan.
Tekshirib ko'ring:
<button onClick={handleClick()}>—handleClickfaqatconsole.log("bosildi")qiladi,setStateyo'q.Too many re-renderschiqadimi? Nima bo'ladi?
Javob
Chiqmaydi: render ichida state o'zgarmaydi, sikl yo'q. Lekin xato baribir bor — "bosildi" har renderda yoziladi, bosganda esa hech narsa bo'lmaydi (onClick ga undefined tushgan). Bu "jim" variant: xabarsiz, faqat belgi bilan tanisa bo'ladi. Davosi o'sha — onClick={handleClick} yoki onClick={() => handleClick()}.
4. Effekt xatolari
4.1 Cheksiz effekt sikli
Bog'liqliklar massivisiz effekt har commit'dan keyin ishlaydi (useEffect II). U ichida state o'zgartirsa — yangi render, yangi commit, yana effekt. Quyidagi misolda biz sikl 60 da to'xtashi uchun shart qo'ydik (aks holda u abadiy aylanadi):
import { useEffect, useState } from "react";
function App() {
const [n, setN] = useState(0);
useEffect(() => {
if (n < 60) setN(n + 1); // ❌ bog'liqliklarsiz effektda setState
});
return <p>Render: {n}</p>;
}Konsolda:
Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.Ekranda:
Render: 60"Yangilanishlar chuqurligi oshib ketdi. Komponent useEffect ichida setState chaqirsa va useEffect da bog'liqliklar massivi bo'lmasa yoki bog'liqliklardan biri har renderda o'zgarsa, shunday bo'ladi." React effekt ichidan kelgan ketma-ket yangilanishlarni sanaydi va 50 dan oshganda shu ogohlantirishni beradi. Xatodan farqli o'laroq, u siklni to'xtatmaydi. Shartimiz bo'lmasa, sahifa ishlayveradi, protsessor esa 100% band bo'ladi va telefon qiziydi.
Xabar ikki sababni aytadi. Birinchisi — massiv yo'q (yuqoridagi). Ikkinchisi yashirinroq: massiv bor, lekin bog'liqlik har renderda yangi:
function Menu() {
const [dishes, setDishes] = useState([]);
const filter = { category: "ovqat" }; // ❌ har renderda yangi obyekt
useEffect(() => {
setDishes(loadDishes(filter));
}, [filter]); // Object.is: doim "o'zgardi"
}React bog'liqliklarni Object.is bilan solishtiradi. Ikki xil obyekt — mazmuni bir xil bo'lsa ham — "har xil". Davolari, eng yaxshisidan boshlab:
- Effekt umuman kerakmi? Ma'lumot props'dan hisoblanadigan bo'lsa — renderda hisoblang (Sizga effekt kerak emas).
- Bog'liqlikka obyekt emas, primitiv bering:
[filter.category]. - Obyektni komponentdan tashqarida e'lon qiling yoki effekt ichiga ko'chiring.
- Oxirgi chora —
useMemo(memo, useMemo, useCallback).
4.2 Eskirgan closure (stale closure)
Bu — jim xato. Xabar yo'q, ekran shunchaki to'xtaydi:
import { useEffect, useState } from "react";
function App() {
const [sec, setSec] = useState(0);
useEffect(() => {
const id = setInterval(() => setSec(sec + 1), 100);
return () => clearInterval(id);
}, []); // ❌ sec — birinchi renderdagi 0
return <p>Osh tayyor bo'lishiga: {sec} s</p>;
}Ekranda:
Osh tayyor bo'lishiga: 1 sTaymer 450 ms ichida to'rt marta ishladi, ekranda esa doim 1. Sabab — snapshot: interval funksiyasi birinchi renderda yasalgan va o'sha renderdagi sec ni — 0 ni — "ushlab qolgan". Har safar u setSec(0 + 1) deydi. Bo'sh massiv [] effektni qayta yasamaydi, demak yangi sec ni ko'radigan funksiya hech qachon paydo bo'lmaydi.
Davosi — updater funksiya: "joriy qiymatni sen ber, men unga 1 qo'shaman":
import { useEffect, useState } from "react";
function App() {
const [sec, setSec] = useState(0);
useEffect(() => {
const id = setInterval(() => setSec((s) => s + 1), 100);
return () => clearInterval(id);
}, []); // ✅ eski qiymatga tayanmaydi
return <p>Osh tayyor bo'lishiga: {sec} s</p>;
}Ekranda:
Osh tayyor bo'lishiga: 4 sEskirgan closure faqat taymerda emas. Uning uyalari: setInterval, addEventListener dagi ishlovchi, useCallback(…, []) va bog'liqliklari to'liq bo'lmagan har qanday effekt. ESLint'ning react-hooks/exhaustive-deps qoidasi ko'p holatni ushlaydi — shuning uchun uni o'chirib qo'ymang (pastda «Davoning o'zi xato bo'lsa» bo'limida). Effektda eng so'nggi qiymatni o'qish, lekin effektni qayta ishga tushirmaslik kerak bo'lsa — useEffectEvent.
Tekshirib ko'ring: Eskirgan closure misolida massivga
[sec]qo'yilsa, taymer ishlaydimi? Updater variantidan nimasi yomonroq?
Javob
Ishlaydi: har sec o'zgarganda effekt tozalanadi va yangi sec bilan yangi interval yasaladi. Lekin har soniyada interval o'chirilib qayta yoqiladi — ortiqcha ish. Bundan tashqari interval har safar noldan sanaydi, shuning uchun ritm buziladi. Updater variantida bitta interval butun umr ishlaydi va hech qanday qiymatni "ushlab" qolmaydi.
5. State bilan ishlashdagi xatolar
5.1 Mutatsiya — ekran yangilanmaydi
import { useState } from "react";
function App() {
const [order, setOrder] = useState(["Osh"]);
function addManti() {
order.push("Manti"); // ❌ eski massivni o'zgartirdi
setOrder(order); // o'sha massiv — React "o'zgarmadi" deydi
console.log(order);
}
return (
<div>
<p>Buyurtma: {order.join(", ")}</p>
<button onClick={addManti}>Manti qo'shish</button>
</div>
);
}Konsolda:
(2) ['Osh', 'Manti']Ekranda:
Buyurtma: Osh
Manti qo'shishKonsolda massivda ikki taom, ekranda — bitta. Bu ziddiyat mutatsiyaning aniq belgisi. React setOrder(order) ni Object.is(eski, yangi) bilan tekshiradi: havola o'sha — "o'zgarish yo'q", render bo'lmaydi. Davosi — har doim yangi massiv yoki obyekt (State III):
import { useState } from "react";
function App() {
const [order, setOrder] = useState(["Osh"]);
function addManti() {
setOrder((o) => [...o, "Manti"]); // ✅ yangi massiv
}
return (
<div>
<p>Buyurtma: {order.join(", ")}</p>
<button onClick={addManti}>Manti qo'shish</button>
</div>
);
}Ekranda:
Buyurtma: Osh, Manti
Manti qo'shishMutatsiyaning yana bir yuzi bor: ekran keyinroq, boshqa sabab bilan yangilanganda o'zgarish birdan chiqadi. "Tugma ishlamadi, keyin boshqasini bossam — paydo bo'ldi" — shu belgi. memo va useMemo esa mutatsiya bilan butunlay adashadi (memo, useMemo, useCallback). Mutatsiyalar ko'p joyda yashirinadi: sort(), reverse(), splice() — ular asl massivni o'zgartiradi. Ularning nusxa qaytaradigan juftlari bor: toSorted(), toReversed(), toSpliced().
5.2 Controlled va uncontrolled almashishi
import { useState } from "react";
function App() {
const [form, setForm] = useState({}); // ❌ form.name — undefined
return (
<input
placeholder="Ism"
value={form.name}
onChange={(e) => setForm({ name: e.target.value })}
/>
);
}Konsolda:
A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://react.dev/link/controlled-components"Komponent uncontrolled input'ni controlled'ga aylantiryapti. Ehtimol value undefined dan aniq qiymatga o'zgargan — bunday bo'lmasligi kerak. Komponent umri davomida bittasini tanlang." Birinchi renderda value={undefined} — React uchun bu "value umuman yo'q", ya'ni uncontrolled maydon (Formalar I). Birinchi harfdan keyin value="M" — endi controlled. Rejim o'rtada almashdi.
Davosi — boshlang'ich qiymat: useState({ name: "" }) yoki value={form.name ?? ""}. Teskari yo'nalish ham bor: value qiymatdan undefined ga o'tsa, A component is changing a controlled input to be uncontrolled chiqadi. Odatda sababi serverdan kelgan ma'lumotda null maydonda bo'ladi. Bu qoida sizning komponentlaringizga ham tegishli — Controlled va uncontrolled komponent API dizayni darsida o'zingiz shunday rejimli komponent yasaysiz.
6. Ro'yxat va key
6.1 Kalitsiz va takror kalit
const MENU = ["Osh", "Manti"];
function App() {
return <ul>{MENU.map((d) => <li>{d}</li>)}</ul>;
}Konsolda:
Each child in a list should have a unique "key" prop.
Check the render method of `App`. See https://react.dev/link/warning-keys for more information."Ro'yxatdagi har bola noyob key props'iga ega bo'lishi kerak. App ning render metodini tekshiring." Ikkinchi qator komponentni aytadi. Takror kalit — boshqa xabar:
const MENU = ["Osh", "Osh", "Manti"];
function App() {
return <ul>{MENU.map((d) => <li key={d}>{d}</li>)}</ul>;
}Konsolda:
Encountered two children with the same key, `Osh`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version."Bir xil kalitli ikki bola topildi: Osh. Kalitlar noyob bo'lsin — shunda komponentlar yangilanishlar orasida o'z shaxsini saqlaydi. Takror kalit bolalarni ikki marta chizishi yoki tushirib qoldirishi mumkin." Ikki mehmon bir xil taom buyurtma qilsa — nom kalit bo'la olmaydi. Kalit — ma'lumotning id si.
6.2 Indeks kalit — jim xato
Eng xavflisi — ogohlantirishni "o'chirish" uchun key={index} qo'yish. Ogohlantirish yo'qoladi, xato qoladi:
import { useState } from "react";
function Row({ name, onRemove }) {
const [portions, setPortions] = useState(1);
return (
<li>
{name}: {portions} porsiya{" "}
<button onClick={() => setPortions(portions + 1)}>
+ {name}
</button>{" "}
<button onClick={onRemove}>{name} — o'chir</button>
</li>
);
}
function App() {
const [dishes, setDishes] = useState(["Osh", "Manti"]);
return (
<ul>
{dishes.map((d, i) => (
<Row
key={i} // ❌ indeks — o'rin, taom emas
name={d}
onRemove={() => setDishes(dishes.filter((x) => x !== d))}
/>
))}
</ul>
);
}Ekranda:
Manti: 1 porsiya + Manti Manti — o'chirMantiga uch porsiya qo'shdik (1 + 2), Oshni o'chirdik — Mantida esa 1 porsiya. Nima bo'ldi? O'chirishdan oldin: kalit 0 — Osh (1 porsiya), kalit 1 — Manti (3 porsiya). O'chirgandan keyin Manti birinchi o'ringa chiqdi va kalit 0 ni oldi. React kalit 0 dagi komponentni saqlab qoldi — u bilan birga Oshning state'ini (1). Kalit 1 esa yo'qoldi, Mantining 3 porsiyasi u bilan ketdi.
| Kalit 0 | Kalit 1 | |
|---|---|---|
| O'chirishdan oldin | Osh, 1 porsiya | Manti, 3 porsiya |
| Keyin (indeks) | Manti, 1 porsiya — Oshniki | yo'q — 3 porsiya yo'qoldi |
Keyin (key={d}) |
— | Manti, 3 porsiya |
key={d} (yoki haqiqiy id) bilan sinab ko'ring — Mantida 3 porsiya qoladi. Indeks kalit faqat ro'yxat hech qachon qayta tartiblanmasa, o'chirilmasa va qatorlarda state bo'lmasa xavfsiz. Batafsil — Ro'yxatlarni render qilish va key.
Tekshirib ko'ring: Sardor
key={Math.random()}qo'ydi — "noyob-ku!". Ogohlantirish yo'qoldi. Nima buzildi?
Javob
Har renderda hamma kalit yangi. React har qatorni "yangi element" deb ko'radi: eskisini o'chiradi (state, fokus, input matni yo'qoladi) va noldan yaratadi. Bitta harf yozilsa ham butun ro'yxat qayta yasaladi — sekin va maydondagi fokus uchib ketadi. Kalit noyob bo'lishi bilan birga barqaror bo'lishi kerak: bir element — har renderda bir kalit.
7. Katalog: bir jadvalda
| Belgi yoki xabar | Turi | Ildiz sabab | Davo |
|---|---|---|---|
Too many re-renders |
xato | renderda setState, onClick={f()} |
hosilaviy qiymat; onClick={() => f()} |
Cannot update a component (A) while rendering (B) |
ogohl. | bola renderda ota setter'ini chaqiradi | otada hisoblash; hodisada chaqirish |
Objects are not valid as a React child |
xato | obyekt yoki Date JSX'da |
kerakli maydon: .name |
Functions are not valid as a React child |
ogohl. | {f} — chaqirilmagan |
{f()} yoki <F /> |
Rendered more/fewer hooks… |
xato | shart, sikl, erta return dan keyin hook |
hooklar yuqorida, shart — qiymatda |
Maximum update depth exceeded |
ogohl. yoki xato | effektda setState, bog'liqlik har renderda yangi |
massiv; primitiv bog'liqlik; effektsiz |
| Qiymat "qotib qolgan" | jim | eskirgan closure | updater; to'liq bog'liqliklar |
| Konsolda bor, ekranda yo'q | jim | mutatsiya | yangi massiv yoki obyekt |
uncontrolled … to be controlled |
ogohl. | value={undefined} |
?? "" yoki boshlang'ich qiymat |
unique "key", same key |
ogohl. | kalit yo'q yoki takror | ma'lumot id si |
| State qo'shni qatorga ko'chdi | jim | key={index} |
barqaror id |
Maximum update depth exceeded ikki xil bo'ladi. Effektda u ogohlantirish (yuqorida ko'rdik). useLayoutEffect dagi sinxron sikl esa Uncaught Error beradi — ikkinchi qismida componentWillUpdate or componentDidUpdate deb yozilgan. Bu class komponentlar davridan qolgan matn, lekin funksiya komponentlarda ham chiqadi (Class komponentlarni o'qish).
8. Ko'p uchraydigan xatolar: davoning o'zi xato bo'lsa
Katalogni bilish yarim ish. Ikkinchi yarmi — xabarni yo'qotish emas, sababni tuzatish. Sardorning uchta "tezkor davosi" va ular nimani yashiradi:
| "Davo" | Nimani yashiradi | To'g'risi |
|---|---|---|
// eslint-disable-next-line react-hooks/exhaustive-deps |
eskirgan closure yoki keraksiz effekt | effektni qayta o'ylash: kerakmi, updater, useEffectEvent |
<StrictMode> ni olib tashlash ("effekt ikki marta ishlayapti") |
cleanup'siz effekt — production'da ham sizib chiqadi | cleanup yozish (StrictMode chuqur) |
key={index} yoki key={Math.random()} |
identifikatsiya yo'qligi | ma'lumotdagi barqaror id |
try/catch render atrofida |
renderdagi xato try ga tushmaydi — bola komponentlar keyin chiziladi |
Error boundary |
useRef bayrog'i: "effekt ikkinchi marta ishlamasin" |
StrictMode ko'rsatgan cleanup yo'qligi |
cleanup; qayta ishlashga chidamli effekt |
Umumiy qoida: ogohlantirish — alomat. Haroratni tushiradigan dori kasallikni davolamaydi. ESLint qoidasini o'chirishdan oldin o'zingizga savol bering: "U nima demoqchi?" Ko'pincha javob — "bu effekt kerak emas".
9. Mashqlar
Mashqlar kurs/mashqlar/18/25-react-xatolari/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): xabardan sababga
Har xabar yoki belgi uchun ildiz sababni yozing (render, closure, mutatsiya, key, undefined — shu so'zlardan biri):
Too many re-renders— renderda chaqirilgan setter:- Taymer ekranda 1 da to'xtab qoldi, xabar yo'q:
console.logda yangi taom bor, ekranda yo'q:- O'chirgandan keyin porsiya soni qo'shni taomga o'tdi:
changing an uncontrolled input to be controlled:
Yechim
Birinchisi — render paytidagi setState («Too many re-renders» bo'limi). Ikkinchisi — eskirgan closure: taymer funksiyasi birinchi renderdagi qiymatni ushlab qolgan. Uchinchisi — mutatsiya: massiv o'zgardi, havola esa o'sha, React render qilmadi. To'rtinchisi — indeks kalit: state o'ringa yopishgan, taomga emas. Beshinchisi — value boshida undefined edi.
2-mashq (o'rta): navbat taymeri
«Bahor» oshxonasida navbat raqami har 100 ms da bittaga oshishi kerak. Lekin ekranda raqam 1 da qotib qoladi. Tuzating — 450 ms dan keyin Navbat: 4 chiqsin. Ishora: «Eskirgan closure» bo'limi — updater funksiya.
import { useEffect, useState } from "react";
function App() {
const [ticket, setTicket] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setTicket(ticket + 1);
}, 100);
return () => clearInterval(id);
}, []);
return <p>Navbat: {ticket}</p>;
}Ekranda:
Navbat: 1Yechim
import { useEffect, useState } from "react";
function App() {
const [ticket, setTicket] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setTicket((t) => t + 1); // ✅ joriy qiymatdan
}, 100);
return () => clearInterval(id);
}, []);
return <p>Navbat: {ticket}</p>;
}Ekranda:
Navbat: 4Interval funksiyasi birinchi renderda yasalgan va ticket = 0 ni ushlab qolgan edi. Updater funksiya ticket ni o'qimaydi — React unga joriy qiymatni o'zi beradi. [ticket] bog'liqligi ham ishlardi, lekin har qadamda intervalni qayta yasardi.
3-mashq (qiyin): uch xatoli savat
Sardor savat yozdi. Unda uchta xato bor: konsolda ikkita ogohlantirish chiqadi, «Choy qo'shish» tugmasi esa ekranni yangilamaydi. Uchalasini tuzating: konsol toza bo'lsin, ikki marta bosilgandan keyin ekranda uch taom va to'g'ri jami chiqsin.
Ishora: «Katalog: bir jadvalda» — har belgini qatoriga moslang. Mutatsiya uchun — State III, key uchun — taomning id si.
import { useState } from "react";
let nextId = 3;
function App() {
const [cart, setCart] = useState([
{ id: 1, name: "Osh", price: 35000 },
{ id: 2, name: "Manti", price: 30000 },
]);
const [note, setNote] = useState();
function addTea() {
cart.push({ id: nextId++, name: "Ko'k choy", price: 5000 });
setCart(cart);
}
const total = cart.reduce((s, d) => s + d.price, 0);
return (
<div>
<ul>
{cart.map((d) => (
<li>{d.name} — {d.price}</li>
))}
</ul>
<p>Jami: {total} so'm</p>
<input
placeholder="Izoh"
value={note}
onChange={(e) => setNote(e.target.value)}
/>
<button onClick={addTea}>Choy qo'shish</button>
</div>
);
}Konsolda:
Each child in a list should have a unique "key" prop.
Check the render method of `App`. See https://react.dev/link/warning-keys for more information.Ekranda:
Osh — 35000
Manti — 30000
Jami: 65000 so'm
Choy qo'shishKonsolda hozircha bitta ogohlantirish. Ikkinchisi (uncontrolled … to be controlled) izoh maydoniga birinchi harf yozilganda chiqadi — «Ishga tushir» bilan yozib ko'ring.
Yechim
import { useState } from "react";
let nextId = 3;
function App() {
const [cart, setCart] = useState([
{ id: 1, name: "Osh", price: 35000 },
{ id: 2, name: "Manti", price: 30000 },
]);
const [note, setNote] = useState(""); // ✅ boshidan satr
function addTea() {
const tea = { id: nextId++, name: "Ko'k choy", price: 5000 };
setCart((c) => [...c, tea]); // ✅ yangi massiv
}
const total = cart.reduce((s, d) => s + d.price, 0);
return (
<div>
<ul>
{cart.map((d) => (
<li key={d.id}>{d.name} — {d.price}</li> // ✅ id
))}
</ul>
<p>Jami: {total} so'm</p>
<input
placeholder="Izoh"
value={note}
onChange={(e) => setNote(e.target.value)}
/>
<button onClick={addTea}>Choy qo'shish</button>
</div>
);
}Ekranda:
Osh — 35000
Manti — 30000
Ko'k choy — 5000
Ko'k choy — 5000
Jami: 75000 so'm
Choy qo'shishUch tuzatish: key={d.id} (ikki choy bir xil nomli — nom kalit bo'la olmasdi), setCart((c) => [...c, tea]) (yangi massiv — React o'zgarishni ko'radi) va useState("") (izoh maydoni boshidan controlled). Diqqat: tea obyekti updater'dan tashqarida yasaladi. nextId++ ni updater ichiga qo'ysangiz, StrictMode dev'da updater'ni ikki marta chaqiradi va id'lar sakrab ketadi. Updater sof bo'lishi kerak (StrictMode chuqur).
10. Real ishda
- Kod ko'rigi (code review): katalogdagi jim xatolar — ko'rikda eng ko'p topiladigan narsalar. Jasur aka PR'da birinchi navbatda
key={index},push/sortvaeslint-disableqatorlarini qidiradi. - Sentry va xato kuzatuvi: production'da ogohlantirishlar yo'q, faqat
Uncaught Errorlar keladi. Ular qisqartirilgan bo'ladi: masalanMinified React error #301va havola — buToo many re-renders. Raqamni react.dev'dagi ro'yxatdan ochasiz — matni shu katalogdagilar. - ESLint:
eslint-plugin-react-hooks(kanonda 7.1.1) katalogning uchdan birini kod yozayotganda ushlaydi: hooklar qoidasi, bog'liqliklar, renderdasetState. React Compiler lint qoidalari ham shu plaginda (React Compiler). - Intervyu savollari: "Nega
key={index}yomon?", "Stale closure nima va qanday tuzatiladi?", "Too many re-rendersqachon chiqadi?", "Nega state'ni mutatsiya qilib bo'lmaydi?".
Xulosa
- Har xabarga uch savol: xatomi yoki ogohlantirishmi, qaysi bosqichda, qaysi komponentda.
- Render sof bo'lsin: renderda
setState, ota setter'ini chaqirish, shartdagi hook — hammasi xato yoki ogohlantirish beradi. - Effektda
setState— bog'liqliklar massivi va barqaror (primitiv) bog'liqliklar bilan; aks holdaMaximum update depth exceeded. - Jim xatolar — eskirgan closure (updater bilan davolanadi), mutatsiya (yangi massiv), indeks kalit (barqaror
id). valuehech qachonundefinedbo'lmasin — maydon rejimi umr bo'yi bitta.- Ogohlantirishni yashirmang (
eslint-disable,StrictModesiz, tasodifiykey) — sababini tuzating.
Keyingi dars: Compound komponentlar va slot naqshi — bir-biriga bog'langan komponentlar umumiy holatni Context orqali qanday bo'lishishi.
Manbalar
- React: "Common pitfalls" — react.dev/reference/react/useState#troubleshooting
- React:
useEffecttroubleshooting — react.dev/reference/react/useEffect#troubleshooting - React: "Rules of Hooks" — react.dev/reference/rules/rules-of-hooks
- React: "Rendering Lists" (key) — react.dev/learn/rendering-lists
- React xato kodlari (minified) — react.dev/errors
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!