Error Handling — error.tsx, global-error.tsx, try/catch

~15 daq · Next.js · Ma'lumot Olish

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.