Error Boundary — xatolarni ushlash, fallback UI
Muammodan boshlaylik
Mahsulot sahifasida "Sharhlar" bloki bor. Server bitta sharhni noto'g'ri formatda qaytardi:
function Sharh({ sharh }) {
return <p>{sharh.muallif.ism}: {sharh.matn}</p>; // muallif — null
}
TypeError: Cannot read properties of null (reading 'ism')
Natija: butun sahifa oq bo'lib qoldi. Header ham, mahsulot rasmi ham, "Savatga" tugmasi ham — hammasi yo'qoldi. Bitta sharhdagi xato tufayli foydalanuvchi mahsulotni sotib ololmaydi.
Bu React ning standart xatti-harakati: render paytida xato bo'lsa, React butun daraxtni olib tashlaydi — chunki buzilgan UI ni ko'rsatish (noto'g'ri narx, boshqa foydalanuvchining ma'lumoti) bo'sh ekrandan ham xavfliroq.
Lekin biz xatoni cheklashni xohlaymiz: sharhlar ishlamasa — faqat sharhlar o'rnida xabar, sahifaning qolgan qismi ishlayversin. Buning uchun — Error Boundary.
Error Boundary nima
Error Boundary — bola komponentlaridagi render xatolarini ushlaydigan va ular o'rniga zaxira UI (fallback) ko'rsatadigan komponent. JavaScript dagi try/catch ga o'xshaydi, lekin komponentlar daraxti uchun.
<Header />
<MahsulotMalumoti />
<ErrorBoundary fallback={<p>Sharhlarni yuklab bo'lmadi.</p>}>
<Sharhlar /> {/* xato shu yerda qoladi */}
</ErrorBoundary>
<Footer />
Sharhlar ichida xato bo'lsa — faqat shu blok fallback ga almashadi.
Class komponent bilan
Error Boundary — React da hali ham faqat class komponent bilan yoziladigan yagona narsa (hook ekvivalenti yo'q):
import { Component } from 'react';
class ErrorBoundary extends Component {
state = { xato: null };
static getDerivedStateFromError(xato) {
// Render paytida: fallback ko'rsatish uchun state ni yangilash
return { xato };
}
componentDidCatch(xato, info) {
// Xatoni qayd qilish — konsol yoki monitoring xizmati
console.error(xato, info.componentStack);
}
render() {
if (this.state.xato) {
return this.props.fallback;
}
return this.props.children;
}
}
| Metod | Vazifasi |
|---|---|
static getDerivedStateFromError(xato) |
Xato bo'lganda yangi state qaytaradi → fallback |
componentDidCatch(xato, info) |
Qo'shimcha amallar: loglash; info.componentStack — qaysi komponentda |
Uni bir marta yozib, butun ilovada ishlatasiz.
react-error-boundary — tayyor yechim
Amalda ko'pincha tayyor kutubxona ishlatiladi:
npm install react-error-boundary
import { ErrorBoundary } from 'react-error-boundary';
function XatoBloki({ error, resetErrorBoundary }) {
return (
<div role="alert">
<p>Nimadir noto'g'ri ketdi.</p>
<pre style={{ color: 'red' }}>{error.message}</pre>
<button onClick={resetErrorBoundary}>Qayta urinish</button>
</div>
);
}
<ErrorBoundary
FallbackComponent={XatoBloki}
onError={(error, info) => logXizmati.yubor(error, info)}
onReset={() => {
// qayta urinishdan oldin holatni tozalash
}}
>
<Sharhlar />
</ErrorBoundary>
FallbackComponent— xato bo'lganda ko'rsatiladigan komponent;errorvaresetErrorBoundaryni oladiresetErrorBoundary()— boundary ni tiklaydi va bolalarni qayta render qiladionError— loglash
resetKeys — avtomatik tiklash
const { id } = useParams();
<ErrorBoundary FallbackComponent={XatoBloki} resetKeys={[id]}>
<MahsulotTafsiloti id={id} />
</ErrorBoundary>
resetKeys dagi qiymat o'zgarganda (foydalanuvchi boshqa mahsulotga o'tdi) boundary avtomatik tiklanadi. Busiz xato bloki boshqa sahifada ham qolib ketardi.
[!WARNING] Production da foydalanuvchiga
error.messageyoki stack trace ni ko'rsatmang — u tushunarsiz va ba'zan ichki ma'lumotni (fayl yo'llari, server tafsilotlari) oshkor qiladi. Foydalanuvchiga — oddiy, tushunarli xabar va harakat ("Qayta urinish", "Bosh sahifaga"); tafsilotlar — monitoring xizmatiga (Sentry va boshqalar).
Nimani ushlamaydi
Error Boundary faqat render paytidagi xatolarni ushlaydi:
| Ushlaydi ✅ | Ushlamaydi ❌ |
|---|---|
| Komponent render qilayotganda | Event handler lar (onClick ichida) |
useEffect, useLayoutEffect ichida (sinxron) |
Async kod (setTimeout, fetch().then, await dan keyin) |
| Bola komponentlar konstruktorlari | Server-side rendering |
lazy komponent yuklanmasa (69-dars) |
Error Boundary ning o'zidagi xato |
Event handler dagi xatolar
function SaqlashTugmasi() {
const [xato, setXato] = useState(null);
async function saqla() {
try {
await api.saqla();
} catch (e) {
setXato(e.message); // oddiy try/catch + state
}
}
return (
<>
<button onClick={saqla}>Saqlash</button>
{xato && <p role="alert">{xato}</p>}
</>
);
}
Event handler da xato UI ni buzmaydi — React render paytida emas. Uni oddiy try/catch bilan ushlang.
Async xatoni boundary ga uzatish
Agar async xato boundary orqali ko'rsatilishi kerak bo'lsa:
import { useErrorBoundary } from 'react-error-boundary';
function Profil() {
const { showBoundary } = useErrorBoundary();
useEffect(() => {
api.getProfil().then(setProfil).catch(showBoundary); // eng yaqin boundary ga
}, []);
}
TanStack Query bilan — throwOnError: true parametri xatoni render paytida tashlaydi va eng yaqin boundary ushlaydi.
Qayerga qo'yish kerak
// 1. Ilovaning eng yuqorisida — oxirgi himoya
<ErrorBoundary FallbackComponent={ToliqSahifaXatosi}>
<App />
</ErrorBoundary>
// 2. Har bir sahifa (route) atrofida — bir sahifa buzilsa, navigatsiya ishlaydi
<Layout>
<ErrorBoundary FallbackComponent={SahifaXatosi} resetKeys={[location.pathname]}>
<Suspense fallback={<Skeleton />}>
<Outlet />
</Suspense>
</ErrorBoundary>
</Layout>
// 3. Mustaqil vidjetlar atrofida — sharhlar, grafik, reklama, chat
<ErrorBoundary fallback={<p>Grafik mavjud emas</p>}>
<Grafik />
</ErrorBoundary>
Qoida: boundary ni shunday joylashtiringki, xato bo'lganda iloji boricha ko'p UI ishlab qolsin, lekin fallback mantiqiy bo'lsin (har bir tugma atrofida boundary — ortiqcha).
[!TIP] React Router ning data router idan foydalansangiz (
createBrowserRouter), har bir route uchunerrorElementbor — u o'sha route dagi xatolar uchun o'rnatilgan Error Boundary vazifasini bajaradi.
Monitoring
Production dagi xatolar haqida foydalanuvchilar odatda yozmaydi — shunchaki ketib qoladi. Shuning uchun xatolarni avtomatik yig'ish kerak:
<ErrorBoundary
FallbackComponent={XatoBloki}
onError={(error, info) => {
Sentry.captureException(error, {
extra: { componentStack: info.componentStack },
});
}}
>
React 19 da createRoot ga global ishlov beruvchilar ham berish mumkin:
createRoot(document.getElementById('root'), {
onCaughtError: (error, info) => { /* boundary ushlagan xatolar */ },
onUncaughtError: (error, info) => { /* hech kim ushlamagan xatolar */ },
}).render(<App />);
Nima uchun shunday?
Nima uchun React render xatosida butun ilovani o'chiradi — buzilgan qismni ko'rsatib qo'ysa yaxshiroq emasmi?
Chunki "buzilgan qism" — oldindan aytib bo'lmaydigan holat. Render yarmida to'xtagan komponent noto'g'ri narxni, boshqa foydalanuvchining ma'lumotini yoki ishlamaydigan "To'lash" tugmasini ko'rsatishi mumkin. Foydalanuvchi uchun noto'g'ri ma'lumot — ma'lumot yo'qligidan xavfliroq: bo'sh ekranni ko'rgan odam sahifani yangilaydi; noto'g'ri summani ko'rgan odam esa unga ishonib, to'lov qilishi mumkin. Shuning uchun React xavfsiz tomonni tanlaydi — hammasini olib tashlaydi. Error Boundary esa sizga — ilova muallifiga — "bu qism mustaqil, uning xatosi qolganlarga ta'sir qilmaydi, uning o'rniga mana bu xabarni ko'rsat" deb aniq chegara chizish imkonini beradi.
Xulosa
Eslab qoling:
- Render xatosi — standart holatda butun ilova o'chadi
- Error Boundary — bolalardagi render xatolarini ushlab, fallback UI ko'rsatadi
- Class:
getDerivedStateFromError(fallback) +componentDidCatch(loglash) - Amalda:
react-error-boundary—FallbackComponent,resetErrorBoundary,resetKeys,onError - Ushlamaydi: event handler lar, async kod — ular uchun
try/catch; kerak bo'lsashowBoundary - Joylashuv: ilova ustida, har bir route atrofida, mustaqil vidjetlar atrofida
- Foydalanuvchiga — tushunarli xabar; tafsilotlar — monitoring xizmatiga
Keyingi dars
80-dars: Portals — modal, tooltip uchun, DOM dan tashqariga chiqish