Mundarija (34)
- Bu darsda
- 1. Nega bu kerak?
- 2. Birinchi chegara
- 2.1 Class komponent — nega
- 2.2 Buzuq taom
- 2.3 Ikki metod — ikki bosqich
- 3. Tiklash
- 3.1 "Qayta urinish"
- 3.2 Kalit o'zgarganda — avtomatik
- 4. Chegara nimani ushlaydi
- 4.1 Ushlamaydigan joylar
- 4.2 Action xatosi — ushlanadi
- 4.3 Hodisa xatosini chegaraga yuborish
- 5. react-error-boundary kutubxonasi
- 6. onCaughtError va onUncaughtError
- 6.1 Ildiz darajasidagi "qora quti"
- 7. Chegaralarni qayerga qo'yish
- 7.1 Granularity — mayda yoki yirik
- 7.2 Suspense bilan juftlik
- 8. Vazifalar qadami: ro'yxat va statistika atrofida chegara (holat 08)
- 8.1 XatoChegarasi.tsx
- 8.2 Qayerga qo'yildi
- 8.3 main.tsx — onCaughtError
- 8.4 Haqiqiy o'lchov
- 8.5 Testlar va commit
- 9. Ko'p uchraydigan xatolar
- 10. Mashqlar
- 1-mashq (oson): ushlaydimi?
- 2-mashq (o'rta): sharhlar buzilsa ham menyu ishlasin
- 3-mashq (qiyin): stol tanlansa — tiklansin, «Qayta urinish» ham bo'lsin
- 4-mashq: Vazifalar qadami
- 11. Real ishda
- Xulosa
- Manbalar
Error boundary: React'da xatoni ushlash va tiklash — oq ekran o'rniga "Qayta urinish"
Qisqacha: Render paytida komponent xato tashlasa, React butun ilovani o'chiradi — oq ekran. Error boundary (xato chegarasi) — ichidagi komponentlar xatosini ushlab, butun ilova o'rniga faqat o'z qismida zaxira UI (fallback) ko'rsatadigan komponent. U hozircha faqat class bo'la oladi:
static getDerivedStateFromErrorxatodan keyingi state'ni qaytaradi,componentDidCatchesa xatoni log qiladi. Tiklash — state'ni tozalash ("Qayta urinish" tugmasi yoki kalit o'zgarganda). Chegara render, effekt,useva Action xatolarini ushlaydi, lekin hodisa ishlovchisi vasetTimeoutdagi xatoni ushlamaydi. Ushlangan va ushlanmagan xatolarcreateRootningonCaughtError/onUncaughtErrorsozlamalariga keladi.
Bu darsda
- O'z error boundary'ingizni yozasiz va bitta buzuq komponent butun sahifani o'chirmasligini ko'rasiz.
- "Qayta urinish" va kalit o'zgarganda avtomatik tiklashni (
resetKeys) qo'shasiz. - Chegara nimani ushlaydi, nimani ushlamasligini jonli tekshirasiz — jumladan Action xatolarini.
react-error-boundarykutubxonasini vaonCaughtError/onUncaughtErrorni bilasiz.- Chegaralarni qayerga qo'yishni (granularity) tanlaysiz va
vazifalarda ro'yxat hamda statistikani himoyalaysiz.
Oldin bilishingiz kerak: React ilovani debug qilish, Suspense, Actions, class sintaksisi.
1. Nega bu kerak?
React ilovani debug qilish darsida o'lchagan edik: vazifalar da bitta qator chizishda xato bo'lsa, #ilova ichida 0 element qoladi. Bitta buzuq vazifa — butun ilova yo'q. Forma, filtr, eksport — hammasi ishlayotgan edi, lekin foydalanuvchi ularni ko'rmaydi.
«Bahor» menyusida ham shunday bo'ldi. Bir taomning narxi serverdan null keldi, price.toFixed() xato tashladi va mehmon telefonida bo'sh oq sahifa ko'rdi. 40 ta taomdan bittasi buzuq edi — 39 tasi ham yo'qoldi.
Nega React bunday qattiq? Uning hujjati shunday tushuntiradi: buzuq UI'ni ko'rsatishdan ko'ra hech narsa ko'rsatmaslik xavfsizroq. Noto'g'ri summa ko'rsatgan to'lov sahifasi oq ekrandan yomonroq. Lekin "hamma narsa yoki hech narsa" — juda qo'pol. Bizga o'rtasi kerak: buzuq qism o'rnida xabar, qolgani ishlaydi.
Hayotiy o'xshatish: uydagi elektr shchiti. Har xona o'z avtomatiga ega. Oshxonada choynak qisqa tutashuv qilsa, faqat oshxonaning avtomati tushadi. Mehmonxonada chiroq yonib turadi. Avtomat yo'q uyda esa butun uy qorong'i bo'ladi. Error boundary — shu avtomat. Qaysi xonaga qo'yishni siz tanlaysiz.
2. Birinchi chegara
2.1 Class komponent — nega
Error boundary hozircha faqat class komponent bo'la oladi. Class komponent — funksiya o'rniga JavaScript klassi bilan yozilgan eski uslubdagi komponent. Uni Class komponentlarni o'qish darsida to'liq ko'ramiz. Bugun bitta tayyor qolip yetarli: chegara uchun kerak bo'lgan ikki metodning hook'dagi o'xshashi yo'q. React jamoasi buni hujjatda ochiq aytadi va react-error-boundary kutubxonasini tavsiya qiladi. Uni ham ko'ramiz.
Qolipni o'qishga yordam beradigan uch narsa:
| Class'da | Funksiyada o'xshashi |
|---|---|
this.state = { … } yoki state = { … } maydoni |
useState boshlang'ich qiymati |
this.setState({ … }) |
setX(…) |
render() { return …; } |
komponent funksiyasining return i |
this.props.children |
{ children } prop'i |
2.2 Buzuq taom
import { Component } from "react";
class ErrorBoundary extends Component {
state = { error: null };
// Render paytida: xatodan keyingi state
static getDerivedStateFromError(error) {
return { error };
}
// Commit'dan keyin: xatoni log qilish
componentDidCatch(error, info) {
console.log("log serverga:", error.message);
}
render() {
if (this.state.error) {
return <p role="alert">Bu taomni ko'rsatib bo'lmadi.</p>;
}
return this.props.children;
}
}
function Dish({ name, price }) {
return (
<li>
{name} — {price.toFixed(0)} so'm
</li>
);
}
export default function App() {
return (
<ul>
<Dish name="Osh" price={35000} />
<ErrorBoundary>
<Dish name="Lag'mon" price={null} />
</ErrorBoundary>
<Dish name="Manti" price={30000} />
</ul>
);
}Konsolda:
TypeError: Cannot read properties of null (reading 'toFixed')
The above error occurred in the <Dish> component.
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.
log serverga: Cannot read properties of null (reading 'toFixed')Ekranda:
Osh — 35000 so'm
Bu taomni ko'rsatib bo'lmadi.
Manti — 30000 so'mLag'mon o'rnida — xabar, osh va manti joyida. Chegarasiz bu misol "Komponentni chizishda xato" qutisi bilan tugardi.
Konsoldagi dastlabki uch qatorni React o'zi yozdi (dev'da). Tarjimasi: "Yuqoridagi xato <Dish> komponentida yuz berdi. React bu komponentlar daraxtini siz bergan ErrorBoundary chegarasi yordamida boshidan qayta yaratishga harakat qiladi." To'rtinchisi — bizning componentDidCatch.
2.3 Ikki metod — ikki bosqich
Nega ikkita metod? Ular React ishining ikki bosqichiga to'g'ri keladi (Pure komponentlar dagi render va commit):
| Metod | Qachon | Nima qiladi | Qoida |
|---|---|---|---|
static getDerivedStateFromError(error) |
render bosqichida | yangi state qaytaradi | sof: faqat return, yon ta'sir yo'q |
componentDidCatch(error, info) |
commit'dan keyin | log, analitika | yon ta'sir mumkin; info.componentStack bor |
static — metod klassning o'ziga tegishli, nusxaga emas (static a'zolar). Shuning uchun uning ichida this yo'q: u faqat xatoni oladi va state qaytaradi. Render bosqichida React yon ta'sirni xohlamaydi — StrictMode uni ikki marta chaqirishi mumkin. Log esa commit'dan keyin, bir marta.
flowchart TD
A["Dish render: throw"] --> B["React: eng yaqin chegara?"]
B -- "topildi" --> C["getDerivedStateFromError → error"]
C --> D["Chegara qayta render: fallback"]
D --> E["Commit"]
E --> F["componentDidCatch: log"]
B -- "yo'q" --> G["Ildiz bo'shaydi, onUncaughtError"]Diagrammadagi ikki yo'lga qarang. Chegara bor — xato qisman. Yo'q — butun ildiz bo'shaydi, xato onUncaughtError ga ketadi (React ilovani debug qilish).
Tekshirib ko'ring:
getDerivedStateFromErrorichidafetch("/log", …)bilan xatoni serverga yuborish yaxshi fikrmi?
Javob
Yo'q. Bu metod render bosqichida ishlaydi va sof bo'lishi kerak. React render'ni qayta urinishi yoki StrictMode'da ikki marta chaqirishi mumkin — log ikki marta ketadi. Yon ta'sir (log, analitika) — componentDidCatch da: u commit'dan keyin, bir marta.
3. Tiklash
3.1 "Qayta urinish"
Xato ko'pincha vaqtinchalik: server bir lahza noto'g'ri javob berdi, keyingi so'rov to'g'ri bo'ladi. Chegara state'ini tozalasak, React ichidagi komponentlarni qaytadan chizadi. Tugmali chegara:
import { Component } from "react";
class ErrorBoundary extends Component {
state = { error: null };
static getDerivedStateFromError(error) {
return { error };
}
// arrow funksiya — this doim shu chegara
reset = () => {
this.setState({ error: null });
};
render() {
if (this.state.error) {
return (
<div role="alert">
<p>Narxlar yuklanmadi.</p>
<button onClick={this.reset}>Qayta urinish</button>
</div>
);
}
return this.props.children;
}
}
// "Server" 200 ms dan keyin tiklanadi
let serverUp = false;
setTimeout(() => {
serverUp = true;
}, 200);
function Prices() {
if (!serverUp) throw new Error("tarmoq uzildi");
return <p>Osh — 35000 so'm</p>;
}
export default function App() {
return (
<ErrorBoundary>
<Prices />
</ErrorBoundary>
);
}Konsolda:
Error: tarmoq uzildi
The above error occurred in the <Prices> component.
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.Ekranda:
Osh — 35000 so'mOchilishda server "ishlamayapti" — ekran("Narxlar yuklanmadi.") fallback'ni tasdiqladi. 200 ms da server tiklandi, lekin ekranda hali xabar: chegara o'z-o'zidan qayta urinmaydi. «Qayta urinish» — reset state'ni tozaladi, React Prices ni yangidan chizdi va narx chiqdi.
Bilish foydali bir detal: React xatoni ko'rganda chegarani darhol qo'llamaydi. Avval butun daraxtni yana bir marta, sinxron chizib ko'radi. Ikkinchi urinish ham xato bersa — fallback. Muvaffaqiyatli bo'lsa, React o'zi tiklanadi va buni onRecoverableError ga yozadi (pastda, «onCaughtError va onUncaughtError» bo'limida).
reset — arrow funksiya maydoni. Oddiy metod bo'lganda onClick={this.reset} ichida this yo'qolardi (this yo'qolishi). Class komponentlarda bu eng ko'p uchraydigan tuzoq — Class komponentlarni o'qish da qaytamiz.
3.2 Kalit o'zgarganda — avtomatik
Ba'zan tugma kerak emas: ma'lumot o'zgarsa, xato ham o'tib ketgan bo'lishi mumkin. Masalan, mehmon boshqa taomni tanladi — eski taomning xatosini ko'rsatib turishning ma'nosi yo'q. Chegaraga tiklash kaliti beramiz. U o'zgarsa — chegara o'zi tozalanadi. Kutubxonalarda bu resetKeys deyiladi:
import { Component, useState } from "react";
class ErrorBoundary extends Component {
state = { error: null };
static getDerivedStateFromError(error) {
return { error };
}
// Kalit o'zgardi va xato bor — tiklaymiz
componentDidUpdate(prevProps) {
if (
this.state.error &&
!Object.is(prevProps.resetKey, this.props.resetKey)
) {
this.setState({ error: null });
}
}
render() {
if (this.state.error) {
return <p role="alert">{this.state.error.message}</p>;
}
return this.props.children;
}
}
const PRICES = { Osh: null, Manti: 30000 };
function DishPrice({ dish }) {
const price = PRICES[dish];
if (price === null) throw new Error(`${dish}: narx yo'q`);
return <p>{dish} — {price} so'm</p>;
}
export default function App() {
const [dish, setDish] = useState("Osh");
return (
<div>
<button onClick={() => setDish("Osh")}>Osh</button>{" "}
<button onClick={() => setDish("Manti")}>Manti</button>
<ErrorBoundary resetKey={dish}>
<DishPrice dish={dish} />
</ErrorBoundary>
</div>
);
}Konsolda:
Error: Osh: narx yo'q
The above error occurred in the <DishPrice> component.
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.Ekranda:
Osh Manti
Manti — 30000 so'mBirinchi ochilishda osh xato berdi — chegara ichida xabar. «Manti» bosildi, resetKey o'zgardi va chegara o'zi tiklandi. Object.is — === ning eng aniq shakli (NaN ni o'ziga teng deb biladi): React ham bog'liqliklarni shu bilan solishtiradi (Dependency massivi). vazifalar kanonidagi tiklashKaliti — aynan shu naqsh.
Muqobil yo'l ham bor — key (State'ning saqlanishi va key): <ErrorBoundary key={dish}>. Kalit o'zgarsa, React chegarani butunlay yangidan yaratadi. Ishlaydi, lekin ichidagi hamma state ham yo'qoladi. resetKey esa faqat xato bo'lganda tiklaydi.
4. Chegara nimani ushlaydi
4.1 Ushlamaydigan joylar
Chegara faqat React'ning o'zi chaqirgan kodni ushlaydi: render, effektlar, ref callback'lar, use, Action'lar. Siz o'zingiz chaqirgan kod — hodisa ishlovchisi, taymer — chegaradan o'tmaydi:
import { Component } from "react";
class ErrorBoundary extends Component {
state = { error: null };
static getDerivedStateFromError(error) {
return { error };
}
render() {
if (this.state.error) return <p role="alert">Chegara ushladi</p>;
return this.props.children;
}
}
function OrderButton() {
function handleClick() {
throw new Error("Hodisada xato"); // ❌ chegara ko'rmaydi
}
return <button onClick={handleClick}>Buyurtma</button>;
}
export default function App() {
return (
<ErrorBoundary>
<OrderButton />
</ErrorBoundary>
);
}Konsolda:
Uncaught Error: Hodisada xato
Error: Hodisada xatoEkranda "Chegara ushladi" yo'q — tugma joyida. Xato window ning error hodisasiga ketdi (Ushlanmagan xatolar). Sababi oddiy: bosish paytida React render qilmayapti. Hodisa ishlovchisi — oddiy JavaScript funksiyasi, uni brauzer chaqiradi. Ilova yiqilmadi ham: render buzilmagan, ekran to'g'ri.
| Xato qayerda | Chegara ushlaydimi | Nima qilish kerak |
|---|---|---|
| render (komponent tanasi) | ha | — |
useEffect, useLayoutEffect, ref callback |
ha | — |
use(promise) — rad etilgan Promise |
ha | — |
<form action>, useTransition dagi Action |
ha | — |
lazy komponent yuklanmadi |
ha | keyingi dars |
hodisa ishlovchisi (onClick) |
yo'q | try/catch + state |
setTimeout, fetch().then |
yo'q | try/catch yoki chegaraga yuborish |
hook'siz startTransition dagi Action |
yo'q | Action ichida ushlash |
| chegaraning o'zidagi xato | yo'q | yuqoridagi chegara |
| serverda render (SSR) | yo'q | framework vositalari |
4.2 Action xatosi — ushlanadi
Actions darsida Action'dagi throw ilovani o'chirgan edi — chegara yo'q edi. Endi chegara bilan:
import { Component } from "react";
class ErrorBoundary extends Component {
state = { error: null };
static getDerivedStateFromError(error) {
return { error };
}
render() {
if (this.state.error) {
const { message } = this.state.error;
return <p role="alert">Bron saqlanmadi: {message}</p>;
}
return this.props.children;
}
}
async function book() {
await new Promise((resolve) => setTimeout(resolve, 200));
throw new Error("500: server xatosi");
}
export default function App() {
return (
<ErrorBoundary>
<form action={book}>
<button>Bron qilish</button>
</form>
</ErrorBoundary>
);
}Konsolda:
Error: 500: server xatosi
The above error occurred in the <form> component.
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.Ekranda:
Bron saqlanmadi: 500: server xatosiForma Action'i <form> ga bog'langan — React qaysi chegaraga berishni biladi. Konsol ham shuni aytadi: "xato <form> komponentida". useTransition bergan startTransition ham komponentga bog'langan — u ham ushlanadi. Hook'siz startTransition esa hech qaysi komponentga tegishli emas — jadvaldagi "yo'q" qatori.
4.3 Hodisa xatosini chegaraga yuborish
Ba'zan hodisadagi xatoni ham chegara ko'rsatishi kerak: masalan, "Yangilash" tugmasi bosilganda server yiqildi. Buning uchun xatoni render ichiga olib kirish kerak. Mashhur usul — state updater'ida throw:
import { Component, useState } from "react";
class ErrorBoundary extends Component {
state = { error: null };
static getDerivedStateFromError(error) {
return { error };
}
render() {
if (this.state.error) {
return <p role="alert">Chegara: {this.state.error.message}</p>;
}
return this.props.children;
}
}
// Xatoni eng yaqin chegaraga yuboradigan hook
function useShowBoundary() {
const [, setState] = useState(null);
return (error) => {
setState(() => {
throw error; // updater render paytida chaqiriladi
});
};
}
function RefreshButton() {
const showBoundary = useShowBoundary();
function handleClick() {
setTimeout(() => {
showBoundary(new Error("server javob bermadi"));
}, 50);
}
return <button onClick={handleClick}>Yangilash</button>;
}
export default function App() {
return (
<ErrorBoundary>
<RefreshButton />
</ErrorBoundary>
);
}Konsolda:
Error: server javob bermadi
The above error occurred in the <RefreshButton> component.
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.Ekranda:
Chegara: server javob bermadiUpdater funksiya ni React keyingi render paytida chaqiradi. Uning ichidagi throw — render xatosi. Endi chegara uni ko'radi. react-error-boundary dagi useErrorBoundary().showBoundary ichida aynan shu g'oya bor.
Tekshirib ko'ring:
OrderButtonninghandleClickida xatonitry/catchbilan ushlab,catchdathrow errqilsak, chegara uni ushlaydimi?
Javob
Yo'q. Qayta tashlangan xato baribir hodisa ishlovchisidan chiqadi — render emas. Chegaraga yetkazish uchun uni render ichiga olib kirish kerak: «Hodisa xatosini chegaraga yuborish» bo'limidagi showBoundary yoki state'ga yozib, render'da throw.
5. react-error-boundary kutubxonasi
Har loyihada o'z class'ini yozish o'rniga, ko'pchilik react-error-boundary kutubxonasini ishlatadi (2026-10-13 holatiga npm'dagi oxirgi versiya — 6.1.6; React 18 va 19 bilan ishlaydi). U funksiya komponentlar bilan ishlaydigan qulay API beradi. Saytdagi «Ishga tushir» begona paketni yuklamaydi — bu kodni o'z loyihangizda sinang (npm install react-error-boundary):
import {
ErrorBoundary,
useErrorBoundary,
} from "react-error-boundary";
// Fallback — oddiy funksiya komponent
function MenuError({ error, resetErrorBoundary }) {
return (
<div role="alert">
<p>Menyu yuklanmadi: {error.message}</p>
<button onClick={resetErrorBoundary}>Qayta urinish</button>
</div>
);
}
function RefreshButton() {
const { showBoundary } = useErrorBoundary();
async function handleClick() {
try {
await refreshMenu();
} catch (error) {
showBoundary(error); // hodisadagi xato — chegaraga
}
}
return <button onClick={handleClick}>Yangilash</button>;
}
export default function MenuPage({ category }) {
return (
<ErrorBoundary
FallbackComponent={MenuError}
resetKeys={[category]} // kategoriya o'zgarsa — tiklanadi
onReset={() => clearMenuCache()} // tiklashdan oldin
onError={(error, info) => logToServer(error, info)}
>
<Menu category={category} />
<RefreshButton />
</ErrorBoundary>
);
}Bugun qo'lda yozgan hamma narsaning nomi bor:
| Kutubxonada | Darsda qo'lda |
|---|---|
FallbackComponent (error, resetErrorBoundary) |
render dagi fallback + reset |
resetKeys={[…]} |
resetKey + componentDidUpdate |
onError |
componentDidCatch |
useErrorBoundary().showBoundary |
useShowBoundary |
onReset |
reset dan oldingi tozalash |
Kutubxona ichida — o'sha class. Shuning uchun class'ni bir marta o'z qo'lingiz bilan yozganingiz foydali: kutubxona sehr emas.
6. onCaughtError va onUncaughtError
6.1 Ildiz darajasidagi "qora quti"
Chegara xatoni foydalanuvchidan yashiradi. Lekin dasturchi undan xabar topishi kerak — aks holda xato oylab sezilmaydi. React ilovani debug qilish darsida onUncaughtError ni yozgan edik. React 19 da uning juftlari bor:
import { Component } from "react";
import { createRoot } from "react-dom/client";
class ErrorBoundary extends Component {
state = { error: null };
static getDerivedStateFromError(error) {
return { error };
}
render() {
if (this.state.error) return <p role="alert">Xato ushlandi</p>;
return this.props.children;
}
}
function Price() {
throw new Error("narx yo'q");
}
const root = createRoot(document.getElementById("root"), {
onCaughtError(error, info) {
// component stack'ning birinchi qatori: "at Price (manzil)"
const first = info.componentStack.trim().split("\n")[0];
const name = first.split(" (")[0];
console.log("ushlandi:", error.message, "|", name);
},
onUncaughtError(error) {
console.log("ilova yiqildi:", error.message);
},
});
root.render(
<ErrorBoundary>
<Price />
</ErrorBoundary>,
);Konsolda:
ushlandi: narx yo'q | at PriceEkranda:
Xato ushlandionCaughtError berilgach, React'ning standart uch qatorli xabari yo'qoldi — endi log bizning qo'limizda. info.componentStack — xato qaysi komponentlar ichida bo'lgani. Uning birinchi qatori at Price (…): qavs ichida fayl manzili va satr raqami. Ular joyga qarab o'zgaradi, shuning uchun biz faqat komponent nomini chiqardik.
| Sozlama | Qachon chaqiriladi |
|---|---|
onCaughtError |
chegara xatoni ushladi (ilova ishlayapti) |
onUncaughtError |
chegara yo'q, ildiz bo'shadi |
onRecoverableError |
React o'zi tiklandi (masalan, hydration nomuvofiqligi) |
Real loyihada uchalasi xatolarni kuzatish xizmatiga (Sentry va boshqalar) yuboradi — Xatolarni kuzatish: Sentry. Dev'da konsol, production'da — server.
7. Chegaralarni qayerga qo'yish
7.1 Granularity — mayda yoki yirik
Har komponent atrofida chegara — ortiqcha: kod ko'payadi, sahifa "teshik-teshik" bo'ladi. Bitta chegara ildizda — oq ekrandan biroz yaxshi, xolos. To'g'ri javob — foydalanuvchi uchun mustaqil qismlar atrofida:
flowchart TD
R["Ildiz chegarasi: 'Nimadir buzildi, sahifani yangilang'"] --> H["Sarlavha, menyu"]
R --> P["Sahifa chegarasi"]
P --> L["Taomlar ro'yxati chegarasi"]
P --> S["Sharhlar chegarasi"]
P --> F["Buyurtma formasi"]
R --> T["Savat chegarasi"]Diagrammada uch daraja. Ildizdagi — oxirgi himoya, "sahifani yangilang". Sahifa darajasidagi — sahifa buzilsa ham menyu va savat ishlaydi. Ichkaridagilar — sharhlar buzilsa ham, taomlar ro'yxati va forma ishlaydi.
Qaror savollari:
- Bu qism o'zi alohida foydalimi? Sharhlarsiz menyu foydali — sharhlar alohida chegarada. Narxsiz buyurtma formasi foydasiz — ular bitta chegarada.
- Fallback qanday ko'rinadi? Kichik vidjet uchun — bir qator matn. Sahifa uchun — "Qayta urinish" va bosh sahifaga havola.
- Tiklash qanday? Ma'lumot o'zgarsa —
resetKeys. Kod yuklanmasa — sahifani yangilash (keyingi dars).
7.2 Suspense bilan juftlik
Suspense "kutilmoqda" ni, chegara — "xato" ni ko'rsatadi. Ular ko'pincha birga turadi:
<ErrorBoundary fallback={<p>Sharhlar yuklanmadi.</p>}>
<Suspense fallback={<p>Sharhlar yuklanmoqda…</p>}>
<Reviews />
</Suspense>
</ErrorBoundary>Tartib muhim: chegara tashqarida. Shunda Reviews ning Promise'i rad etilsa ham, kutish paytida ham shu qism o'z joyida qoladi.
8. Vazifalar qadami: ro'yxat va statistika atrofida chegara (holat 08)
8.1 XatoChegarasi.tsx
Yangi fayl, kanondan aynan; ba'zi izohlar telefon uchun qatorlarga qayta bo'lingan (TypeScript turlarini React + TS darslarida chuqur ko'ramiz):
// XatoChegarasi.tsx — error boundary (18/#08). Render paytidagi
// xato (komponent throw qildi) butun ilovani oq ekranga
// aylantirmaydi (17/#45 da shunday edi: #ilova ichida 0 element):
// faqat shu chegara ichi fallback'ga almashadi, qolgan ilova
// ishlayveradi.
// Hozircha faqat CLASS komponent bo'la oladi: hooklarda
// getDerivedStateFromError/componentDidCatch o'xshashi yo'q (R-59 —
// class komponentni o'qish shu yerda kerak bo'ladi).
// Ushlamaydi: hodisa ishlovchisidagi xato (onClick), async kod
// (setTimeout, await), chegaraning o'zidagi xato — ular uchun try/catch
import { Component } from "react";
import type { ErrorInfo, ReactNode } from "react";
type Props = {
children: ReactNode;
// Xato bo'lganda nima ko'rinadi; qaytaUrin — chegarani tiklaydi
fallback: (xato: unknown, qaytaUrin: () => void) => ReactNode;
// Bu qiymat o'zgarsa — chegara o'zi tiklanadi (masalan, ro'yxat
// serverdan yangilandi — ehtimol xato ma'lumot ham tuzaldi)
tiklashKaliti?: unknown;
onXato?: (xato: unknown, malumot: ErrorInfo) => void;
};
type Holat = { readonly xato: { readonly qiymat: unknown } | null };
export class XatoChegarasi extends Component<Props, Holat> {
override state: Holat = { xato: null };
// Render bosqichi: xatodan keyingi holat (sof — faqat state
// qaytaradi). { qiymat } o'rami: throw null/undefined bo'lsa ham
// "xato bor" bilinsin
static getDerivedStateFromError(xato: unknown): Holat {
return { xato: { qiymat: xato } };
}
// Commit bosqichi: yon ta'sir (log) — componentStack bilan
override componentDidCatch(xato: unknown, malumot: ErrorInfo): void {
this.props.onXato?.(xato, malumot);
}
override componentDidUpdate(oldingi: Props): void {
if (
this.state.xato !== null &&
!Object.is(oldingi.tiklashKaliti, this.props.tiklashKaliti)
) {
this.qaytaUrin();
}
}
// Arrow — this doim shu nusxa (fallback'dagi tugmaga uzatiladi)
qaytaUrin = (): void => {
this.setState({ xato: null });
};
override render(): ReactNode {
if (this.state.xato !== null) {
return this.props.fallback(
this.state.xato.qiymat,
this.qaytaUrin,
);
}
return this.props.children;
}
}Darsdagi hamma narsa bor: ikki bosqich, tiklashKaliti (resetKeys), arrow qaytaUrin. Ikki yangi detal:
{ qiymat }o'rami. JavaScript'dathrow nullham mumkin.state.xato = nullbo'lsa, "xato yo'q" bilan "null tashlandi" farqlanmay qolardi. O'ram bu ikkisini ajratadi.fallback— funksiya. Har joy o'z fallback'ini beradi va ungaqaytaUrinkeladi. Bu — render prop naqshi (HOC va render props).
8.2 Qayerga qo'yildi
Ikki joy — ikki mustaqil qism. Ro'yxat (App.tsx):
<XatoChegarasi
tiklashKaliti={vazifalar}
fallback={(_xato, qaytaUrin) => (
<div id="royxat-xato" role="alert">
<p>Ro'yxatni ko'rsatishda xato yuz berdi.</p>
<button type="button" onClick={qaytaUrin}>
Qayta urinish
</button>
</div>
)}
>
<ul ref={royxatRef} id="royxat" …>…</ul>
</XatoChegarasi>tiklashKaliti={vazifalar} — ro'yxat serverdan yoki boshqa tabdan yangilansa, chegara o'zi qayta urinadi. Forma, statistika, eksport chegaradan tashqarida — ro'yxat buzilsa ham ishlaydi.
Statistika paneli (StatistikaPaneli.tsx): chegara <Suspense> ning tashqarisida, «Suspense bilan juftlik» bo'limidagidek. use() dagi rad etilgan hisob Promise'i shu yerda ushlanadi. statistika-vadasi.ts ga bitta qator qo'shildi — rad etilgan Promise keshdan o'chadi:
// Rad etilgan Promise keshda qolmasin: «Qayta urinish» (18/#08)
// yangisini so'raydi, eskisini emas
vada.catch(() => kesh.delete(vazifalar));Usiz «Qayta urinish» keshdan o'sha rad etilgan Promise'ni olardi — va yana xato. Bu — use() darsidagi "Xato ham keshlanadi" ogohlantirishi.
8.3 main.tsx — onCaughtError
onCaughtError(xato, malumot) {
console.error(
`Xato ushlandi (chegara): ${xatoMatni(xato)}`,
malumot.componentStack ?? "",
);
},Kanon izohi: "error boundary USHLAGAN xato ham shu yerga keladi — ilova ishlayveradi, lekin xato yashirinib qolmasin". 28-qismda bu yer serverga log yuboradi.
8.4 Haqiqiy o'lchov
Kanonni qurishda vaqtinchalik nusxa yasaldi: ?xato=qator bo'lsa, birinchi vazifa qatori throw qiladi (olchov/xato-chegarasi.mjs, Chrome 155). Natija (natijalar/08-xato-chegarasi.txt):
{"ilovaElementlari":69,"royxatXato":"Ro'yxatni ko'rsatishda xato yuz berdi.Qayta urinish","royxatBor":false,"hisob":"2 ta vazifa qoldi, 1 ta bajarildi"}
qo'shishdan keyin: {"ilovaElementlari":69, …, "hisob":"3 ta vazifa qoldi, 1 ta bajarildi"}#ilova ichida 69 element — v7 da 0 edi. Ro'yxat o'rnida xabar, lekin forma ishladi: vazifa qo'shildi va hisob 2 dan 3 ga o'zgardi. Konsolda — Xato ushlandi (chegara): Sinov: qator chizilmadi va component stack.
- v7 (chegarasiz)oq ekran0 ta
- v8 (XatoChegarasi)faqat ro'yxat o'rnida xabar69 ta
Manba: vazifalar kanoni: 17/#45 o'lchovi va natijalar/08-xato-chegarasi.txt (Chrome 155)
8.5 Testlar va commit
tekshiruv/XatoChegarasi.test.tsx — uch test: ushlash va «Qayta urinish», tiklashKaliti, va hodisa ishlovchisidagi xatoni ushlamasligi (xato window ning error hodisasiga ketadi, fallback yo'q). Uchinchi test — «Ushlamaydigan joylar» jadvalining avtomatik isboti.
git switch -c feat/xato-chegarasi
git add -A
git commitCommit (kanon): feat: ro'yxat va statistika atrofida error boundary, onCaughtError. Tekshiruvlar (haqiqiy, tekshiruv-08.txt): node:test ℹ tests 163, Vitest Tests 36 passed (36) (+3), lint, format, tip — toza. Brauzer — 159/159 (uch marta), e2e-18 — 22/22. Diff: 6 fayl, +229 −29.
Bu qadamda e2e ssenariyda bitta o'zgarish topildi: validatsiya xatosi endi Action natijasi bo'lgani uchun keyingi renderda chiqadi. Ssenariy xato matni paydo bo'lishini kutadigan bo'ldi. Bu — oldingi darsdagi Action'larning natijasi.
9. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| bitta komponent xatosi — oq ekran | chegara yo'q | mustaqil qismlar atrofida chegara |
onClick dagi xatoni chegara ko'rmaydi |
hodisa — render emas | try/catch + state yoki showBoundary |
| «Qayta urinish» — yana o'sha xato | rad etilgan Promise keshda qolgan | rad etilsa keshdan o'chiring |
this.reset ichida this — undefined |
oddiy metod, onClick ga uzatilgan |
arrow funksiya maydoni |
| log ikki marta ketadi | yon ta'sir getDerivedStateFromError da |
log — componentDidCatch yoki onCaughtError da |
| chegara xatosi ham oq ekran | xato fallback'ning o'zida | fallback'ni sodda qiling, yuqorida yana bir chegara |
| boshqa taom tanlansa ham xato qoldi | tiklash kaliti yo'q | resetKeys / tiklashKaliti |
10. Mashqlar
Mashqlar kurs/mashqlar/18/08-error-boundary/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): ushlaydimi?
Har holat uchun ha yoki yo'q:
- Komponent tanasida
JSON.parse("{")xato tashladi. onClickichidaprice.toFixed()xato tashladi.useEffectichidathrow new Error().setTimeout(() => { throw new Error(); }, 100)— effekt ichida.<form action>dagi async Actionthrowqildi.
Yechim
- ha — render paytidagi xato.
- yo'q — hodisa ishlovchisi; xato
windowningerrorhodisasiga ketadi. - ha — effektni React o'zi chaqiradi.
- yo'q — effekt tugagan, taymer keyinroq brauzer tomonidan chaqiriladi.
- ha — forma Action'i
<form>ga bog'langan, React xatoni chegaraga beradi.
2-mashq (o'rta): sharhlar buzilsa ham menyu ishlasin
Sahifada menyu va sharhlar bor. Reviews xato tashlaydi va butun sahifa yo'qoladi. ErrorBoundary class'ini yozing va faqat Reviews ni o'rang: sharhlar o'rnida role="alert" li "Sharhlar vaqtincha mavjud emas." chiqsin, menyu ko'rinib tursin.
function Menu() {
return <p>Menyu: osh, lag'mon, manti</p>;
}
function Reviews() {
throw new Error("sharhlar serveri yiqildi");
}
export default function App() {
return (
<div>
<Menu />
<Reviews />
</div>
);
}Konsolda:
Uncaught Error: sharhlar serveri yiqildiYechim
import { Component } from "react";
class ErrorBoundary extends Component {
state = { error: null };
static getDerivedStateFromError(error) {
return { error };
}
render() {
if (this.state.error) {
return <p role="alert">{this.props.fallbackText}</p>;
}
return this.props.children;
}
}
function Menu() {
return <p>Menyu: osh, lag'mon, manti</p>;
}
function Reviews() {
throw new Error("sharhlar serveri yiqildi");
}
export default function App() {
return (
<div>
<Menu />
<ErrorBoundary fallbackText="Sharhlar vaqtincha mavjud emas.">
<Reviews />
</ErrorBoundary>
</div>
);
}Konsolda:
Error: sharhlar serveri yiqildi
The above error occurred in the <Reviews> component.
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.Ekranda:
Menyu: osh, lag'mon, manti
Sharhlar vaqtincha mavjud emas.Chegara faqat Reviews atrofida — Menu uning tashqarisida. Fallback matni prop orqali: bitta class'ni turli joylarda ishlatish uchun.
3-mashq (qiyin): stol tanlansa — tiklansin, «Qayta urinish» ham bo'lsin
Ikki tugma: «1-stol» va «2-stol». TableBill 1-stol uchun xato tashlaydi ("1-stol: hisob topilmadi"), 2-stol uchun "2-stol: 120000 so'm" chiqaradi. Chegara:
- Fallback'da xato matni (
role="alert") va «Qayta urinish» tugmasi. - Stol o'zgarsa — chegara o'zi tiklansin (
resetKey).
Ishora: «"Qayta urinish"» va «Kalit o'zgarganda — avtomatik» bo'limlari; reset — arrow funksiya maydoni.
Yechim
import { Component, useState } from "react";
class ErrorBoundary extends Component {
state = { error: null };
static getDerivedStateFromError(error) {
return { error };
}
componentDidUpdate(prevProps) {
if (
this.state.error &&
!Object.is(prevProps.resetKey, this.props.resetKey)
) {
this.reset();
}
}
reset = () => {
this.setState({ error: null });
};
render() {
if (this.state.error) {
return (
<div role="alert">
<p>{this.state.error.message}</p>
<button onClick={this.reset}>Qayta urinish</button>
</div>
);
}
return this.props.children;
}
}
const BILLS = { 2: 120000 };
function TableBill({ table }) {
const bill = BILLS[table];
if (bill === undefined) {
throw new Error(`${table}-stol: hisob topilmadi`);
}
return <p>{table}-stol: {bill} so'm</p>;
}
export default function App() {
const [table, setTable] = useState(1);
return (
<div>
<button onClick={() => setTable(1)}>1-stol</button>{" "}
<button onClick={() => setTable(2)}>2-stol</button>
<ErrorBoundary resetKey={table}>
<TableBill table={table} />
</ErrorBoundary>
</div>
);
}Konsolda:
Error: 1-stol: hisob topilmadi
The above error occurred in the <TableBill> component.
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.Ekranda:
1-stol 2-stol
2-stol: 120000 so'mOchilishda 1-stol xato berdi — fallback. «2-stol» bosildi: resetKey 1 → 2, componentDidUpdate chegarani tikladi va 2-stol hisobi chiqdi. «Qayta urinish» 1-stolda yana xato beradi — ma'lumot o'zgarmagan, bu to'g'ri xulq. reset ikki joyda ishlatiladi: tugmada va componentDidUpdate da.
4-mashq: Vazifalar qadami
feat/xato-chegarasi branch'ida XatoChegarasi.tsx ni yarating, ro'yxat va statistika panelini o'rang, main.tsx ga onCaughtError qo'shing, statistika-vadasi.ts da rad etilgan Promise'ni keshdan o'chiring. Uch Vitest testini yozing. Commit qiling va PR oching.
Yechim
Tekshiruv ro'yxati:
npm test— node 163, Vitest 36.lint,format:check,tip— toza.- Qo'lda sinov (keyin qaytaring):
OddiyQatorboshigaif (vazifa.id === 1) throw new Error("Sinov")yozing vanpm run devni oching. Ro'yxat o'rnida xabar, forma ishlaydi, konsoldaXato ushlandi (chegara): Sinovva component stack. - Testdagi "hodisa ishlovchisidagi xatoni ushlamaydi" —
windowerrorhodisasini tinglab,preventDefaultbilan jim qiladi. - Commit —
feat: ro'yxat va statistika atrofida error boundary, onCaughtError. PR'ni birlashtiring.
11. Real ishda
- Har jiddiy React ilovada ildizda bitta "Nimadir buzildi" chegarasi va muhim qismlar atrofida kichikroqlari bor. Kod ko'rigida "bu vidjet yiqilsa, sahifa ham yiqiladimi?" degan savol beriladi.
- Next.js — har marshrut papkasidagi
error.tsxfayli — avtomatik error boundary (Maxsus fayllar). - Sentry —
Sentry.ErrorBoundarykomponenti vaonCaughtError/onUncaughtErrorbilan React 19 integratsiyasi (Xatolarni kuzatish: Sentry). - Intervyu savollari: "Error boundary nima va nega u class?", "nimani ushlamaydi?", "
getDerivedStateFromErrorvacomponentDidCatchfarqi?", "chegaralarni qayerga qo'yasiz?".
Xulosa
- Render xatosi chegarasiz butun ilovani o'chiradi; error boundary uni bir qism bilan cheklaydi.
- Chegara — class:
getDerivedStateFromError(render, sof) +componentDidCatch(commit, log). - Tiklash —
setState({ error: null }): tugma bilan yoki kalit o'zgarganda (resetKeys). - Ushlaydi: render, effekt,
use, forma vauseTransitionAction'lari. Ushlamaydi: hodisa, taymer, hook'sizstartTransition, o'zi. react-error-boundary—FallbackComponent,resetKeys,showBoundary;onCaughtError/onUncaughtError— log uchun.vazifalar:XatoChegarasiro'yxat va statistika atrofida — bitta xatoda 0 o'rniga 69 element.
Keyingi dars: lazy va code splitting — og'ir komponentni kerak bo'lganda yuklash va chunk yuklanmasa nima qilish.
Manbalar
- React:
Component— "Catching rendering errors with an Error Boundary" — react.dev/reference/react/Component (2026-10 holati, React 19.3) - React:
createRoot—onCaughtError,onUncaughtError,onRecoverableError— react.dev/reference/react-dom/client/createRoot react-error-boundary— github.com/bvaughn/react-error-boundary
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!