Error Handling — error.tsx, global-error.tsx, try/catch
Muammodan boshlaylik
Siz mahsulot sahifasini yozdingiz. Foydalanuvchi /products/999 ga kirdi — bunday mahsulot yo'q. API 404 qaytardi. Sahifa "crash" bo'ldi — foydalanuvchi Next.js ning qo'pol xato sahifasini ko'rdi.
Yoki API server vaqtincha ishlamay qoldi. Butun sayt ishlamay qoldi.
Xatolar har doim bo'ladi — tarmoq uzilishi, server muammosi, noto'g'ri ma'lumot. Muhimi — ularni to'g'ri ushlash va foydalanuvchiga tushunarli xabar ko'rsatish.
error.tsx — xatolarni ushlash
error.tsx — page.tsx da xato bo'lganda ko'rsatiladigan fayl. Oldingi darslarda ko'rgan edik, endi chuqurroq ko'ramiz.
// app/products/[id]/error.tsx
'use client' // shart — reset funksiyasi brauzerda ishlaydi
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
return (
<div>
<h2>Xato yuz berdi</h2>
<p>{error.message}</p>
<button onClick={reset}>Qayta urinish</button>
</div>
)
}
reset — sahifani qayta render qilishga urinadi. Tarmoq muammosi bo'lsa — foydalanuvchi "Qayta urinish" bosadi, sahifa qayta yuklanadi.
error.digest — server xatolarida Next.js tomonidan beriladigan noyob ID. Logga yozish uchun foydali, lekin foydalanuvchiga ko'rsatilmaydi.
error.tsx qaysi xatolarni tutmaydi
error.tsx — layout dagi xatolarni tutmaydi. Chunki error.tsx layout ichida joylashadi:
layout.tsx
└── error.tsx ← layout xatosini tuta olmaydi
└── page.tsx
Layout xatosi uchun yuqori darajadagi error.tsx kerak:
app/
├── error.tsx ← app/layout.tsx xatosi uchun
└── dashboard/
├── layout.tsx
├── error.tsx ← dashboard/layout.tsx xatosi uchun emas!
└── page.tsx ← faqat page.tsx xatosi uchun
global-error.tsx — root layout xatosi
app/layout.tsx da xato bo'lsa — app/error.tsx ham ishlamaydi. Buning uchun app/global-error.tsx:
// app/global-error.tsx
'use client'
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
return (
<html>
<body>
<h1>Kutilmagan xato</h1>
<button onClick={reset}>Qayta urinish</button>
</body>
</html>
)
}
global-error.tsx da <html> va <body> bo'lishi shart — u root layout o'rnini bosadi.
try/catch — xatolarni o'zingiz boshqarish
Ba'zan xato bo'lganda sahifani "crash" qilmasdan, muqobil kontent ko'rsatish kerak. Masalan, tavsiyalar yuklanmasa — bo'sh ro'yxat ko'rsatish:
// app/products/[id]/page.tsx
export default async function ProductPage({ params }) {
const { id } = await params
// Asosiy ma'lumot — xato bo'lsa error.tsx ko'rsatiladi
const product = await fetch(`/api/products/${id}`, {
cache: 'no-store'
}).then(r => r.json())
// Qo'shimcha ma'lumot — xato bo'lsa bo'sh massiv
let related = []
try {
related = await fetch(`/api/products/${id}/related`)
.then(r => r.json())
} catch {
// Tavsiyalar yuklanmasa — sahifa ishlaydi, faqat tavsiyalar yo'q
}
return (
<div>
<h1>{product.name}</h1>
{related.length > 0 && <RelatedProducts items={related} />}
</div>
)
}
Asosiy ma'lumot xatosi — error.tsx. Qo'shimcha ma'lumot xatosi — try/catch bilan jimgina o'tkazib yuborish.
notFound() — 404 holati
Mahsulot topilmasa — error.tsx emas, not-found.tsx ko'rsatish kerak:
import { notFound } from 'next/navigation'
export default async function ProductPage({ params }) {
const { id } = await params
const product = await fetch(`/api/products/${id}`).then(r => r.json())
// Mahsulot yo'q — 404
if (!product || product.error) notFound()
return <h1>{product.name}</h1>
}
// app/products/not-found.tsx
import Link from 'next/link'
export default function NotFound() {
return (
<div>
<h2>Mahsulot topilmadi</h2>
<Link href="/products">Barcha mahsulotlar</Link>
</div>
)
}
notFound() — 404 xatosi. error.tsx — 500 xatosi. Ikkalasini aralashtirib yubormaslik kerak.
Xatolarni loglash
Production da xatolarni loglash muhim — Sentry, Datadog yoki oddiy console.error:
// app/dashboard/error.tsx
'use client'
import { useEffect } from 'react'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
useEffect(() => {
// Xatoni log xizmatiga yuborish
console.error('Dashboard xatosi:', error)
// Sentry.captureException(error)
}, [error])
return (
<div>
<h2>Xato yuz berdi</h2>
<p>Muammo haqida xabar oldik.</p>
<button onClick={reset}>Qayta urinish</button>
</div>
)
}
Tez-tez uchraydigan xatolar
1. error.tsx da 'use client' yo'q
// ❌ — xato beradi
export default function Error({ reset }) {
return <button onClick={reset}>Qayta</button>
}
// ✅
'use client'
export default function Error({ reset }) {
return <button onClick={reset}>Qayta</button>
}
2. notFound() o'rniga error.tsx ishlatish
// ❌ — mahsulot yo'q, lekin 500 xatosi ko'rsatiladi
if (!product) throw new Error('Mahsulot topilmadi')
// ✅ — to'g'ri 404
if (!product) notFound()
3. global-error.tsx da <html><body> yo'q
// ❌ — xato beradi
export default function GlobalError({ reset }) {
return <div>Xato</div>
}
// ✅
export default function GlobalError({ reset }) {
return (
<html>
<body>
<div>Xato</div>
</body>
</html>
)
}
Xulosa
error.tsx → page.tsx xatosi uchun, 'use client' shart
global-error.tsx → root layout xatosi, <html><body> shart
notFound() → 404, mahsulot/sahifa topilmasa
try/catch → qo'shimcha ma'lumot xatosi, sahifani crash qilmaslik
Xato turlari:
- Mahsulot topilmadi →
notFound()→not-found.tsx - Server xatosi →
throw→error.tsx - Qo'shimcha ma'lumot xatosi →
try/catch→ muqobil kontent
Keyingi dars
21-dars: TanStack Query — Next.js bilan ishlash, server va client farqi
Client Component da ma'lumot olish uchun eng mashhur kutubxona. Server Component bilan qanday birga ishlatiladi.