IlmHamroh
JavaScript Full-stack/23-qism. Next.js5/43-dars23 daqiqa
Mundarija (36)

Next.js maxsus fayllari: loading.tsx, error.tsx, not-found.tsx va boshqalar

Qisqacha: Next.js'da ba'zi fayl nomlari maxsus: papkaga loading.tsx qo'ysangiz — sahifa atrofida avtomatik <Suspense>, error.tsx — avtomatik xato chegarasi (error boundary), not-found.tsx — "topilmadi" sahifasi bo'ladi. Siz faqat komponent yozasiz, o'rash ishini Next.js o'zi qiladi. notFound() funksiyasi shu sahifani chaqiradi va 404 statusini qaytaradi. error.tsx doim client komponent bo'ladi va production'da server xatosining matnini ko'rmaydi — faqat digest kodini. Root layout'ning o'zi yiqilsa, global-error.tsx ishlaydi.

Bu darsda

  • not-found.tsx yozasiz va notFound() bilan /loyihalar/yoq ga 404 qaytarasiz.
  • error.tsx ning error, digest va retry qismlarini haqiqiy prod va dev natijasi bilan tushuntirasiz.
  • Maxsus fayllar qaysi tartibda ichma-ich o'ralishini chizib bera olasiz.
  • loading.tsx qachon ko'rinishini va qachon ko'rinmasligini bilasiz.
  • Next 16.4 dagi halol topilmani ko'rasiz: noma'lum slug birinchi so'rovda baribir 200.

Oldin bilishingiz kerak: Layout va template, Error boundary, Suspense, Fayl-asosli routing.

1. Nega bu kerak?

Fayl-asosli routing darsida tashvishli bir qator qolgan edi: /loyihalar/yoq — mavjud bo'lmagan loyiha — 200 statusi bilan "Loyiha topilmadi" deydi. Odamga to'g'ri ko'rinadi, Google uchun esa bu oddiy sahifa (soft 404).

Yana ikki muammo bor. /yoq kabi umuman yo'q manzilda Next.js'ning standart inglizcha sahifasi chiqadi: "404: This page could not be found." Kanon tekshiruvida unda 3 ta axe buzilishi topilgan (main yo'q). Va agar sahifa ichida xato bo'lsa (masalan GitHub API javob bermasa), foydalanuvchi nima ko'radi? Hozircha — hech qanday rejamiz yo'q.

React'da bularning hammasini bilasiz. Error boundary — xatoni ushlab, o'rniga zaxira UI ko'rsatadigan komponent. Bu qismda uni o'zbekcha xato chegarasi deymiz. Ehtiyot bo'ling: keyingi darslarda yana bir "chegara" chiqadi — "use client" qo'yilgan client chegarasi. Ular boshqa-boshqa narsa. Suspense — kutish paytida fallback ko'rsatadi. 18-qismda ularni qo'lda yozib, kerakli joyga o'ragandingiz.

Next.js shu ishni fayl nomi bilan qiladi. Papkaga error.tsx qo'ydingizmi — shu papkadagi sahifa xato chegarasi bilan o'raladi. loading.tsx — Suspense bilan. Siz faqat "xato bo'lsa nima ko'rinsin" degan komponentni yozasiz.

Hayotiy o'xshatish: mehmonxona. Xonalar — sahifalar. Har qavatda navbatchi (xato chegarasi) bor: xonada muammo bo'lsa, butun mehmonxonani yopmaydi, faqat o'sha qavatda "ta'mirlanmoqda" belgisini qo'yadi. Qabulxonada esa "bunday xona yo'q" (not-found) va "xonangiz tayyorlanmoqda" (loading) javoblari tayyor turadi.

2. Maxsus fayllar ierarxiyasi

2.1 Qaysi fayl nimani o'raydi

Bitta papka (segment) ichidagi maxsus fayllar Next.js tomonidan doim bir xil tartibda ichma-ich qo'yiladi. Next.js hujjatidagi tartib:

flowchart TB
  L["layout.tsx"] --> T["template.tsx"]
  T --> E["error.tsx — xato chegarasi"]
  E --> S["loading.tsx — Suspense"]
  S --> N["not-found.tsx — 404 UI"]
  N --> P["page.tsx yoki ichki layout"]

JSX'da yozsak, app/loyihalar/[slug]/ segmenti taxminan shunday chiziladi:

tsx
<Layout>
  <Template>
    <ErrorBoundary fallback={<Error />}>
      <Suspense fallback={<Loading />}>
        <NotFoundBoundary fallback={<NotFound />}>
          <Page />
        </NotFoundBoundary>
      </Suspense>
    </ErrorBoundary>
  </Template>
</Layout>

Bu — soddalashtirilgan rasm, Next.js'ning haqiqiy kodi emas. Lekin g'oyasi aynan shu: siz yozgan oddiy komponentlar React'ning tanish o'rovchilariga (xato chegarasi, Suspense) fallback bo'lib tushadi.

Ikki muhim xulosa:

  • error.tsx o'z papkasidagi layout.tsx ni ushlamaydi — layout xato chegarasidan tashqarida turibdi. Layout'dagi xatoni ota papkadagi error.tsx ushlaydi. Root layout'ning esa otasi yo'q — unga global-error.tsx kerak.
  • Ichma-ich papkalarda bu zanjir takrorlanadi: bola segmentning hamma fayllari ota segment page.tsx turgan joyga tushadi. Xato eng yaqin error.tsx da ushlanadi.

Tekshirib ko'ring: app/loyihalar/layout.tsx ichida xato chiqdi. app/loyihalar/error.tsx uni ushlaydimi?

Javob

Yo'q. error.tsx o'z segmentining layout'i ichida turadi, uni o'ramaydi. Xatoni ota segmentdagi (app/error.tsx) xato chegarasi ushlaydi.

2.2 notFound() — bu ham xato

notFound() funksiyasi next/navigation dan keladi. Chaqirilganda u xato tashlaydi, ya'ni funksiyaning qolgan qismi bajarilmaydi. Next.js bu xatoni ichidagi maxsus digest maydonidan taniydi va error.tsx ga emas, not-found.tsx ga yo'naltiradi.

Natija oynasidagi next/navigation — o'quv modeli (Fayl-asosli routing darsida aytilgan), lekin u xatoni Next.js'dagi matn bilan tashlaydi. Bosing va ichiga qarang:

tsx
import { notFound } from "next/navigation";

export default function App() {
  function check() {
    try {
      notFound();
      console.log("bu qator bajarilmaydi");
    } catch (error) {
      const e = error as Error & { digest?: string };
      console.log("message:", e.message);
      console.log("digest:", e.digest);
    }
  }
  return <button onClick={check}>Tekshir</button>;
}

Konsolda:

text
message: NEXT_HTTP_ERROR_FALLBACK;404
digest: NEXT_HTTP_ERROR_FALLBACK;404

notFound() dan keyingi qator ishlamadi — throw dagidek. Ikkita xulosa:

  1. notFound() dan keyin return yozish shart emas. Kanon kodida if (!loyiha) notFound(); — va pastdagi kod loyiha ni bemalol ishlatadi. TypeScript ham buni biladi: notFound turi never qaytaradi.
  2. try/catch ichida chaqirmang. O'z catch ingiz uni oddiy xato deb yutib yuboradi va Next.js 404 ni ko'rmaydi. redirect() ham xuddi shunday ishlaydi (Navigatsiya darsida).

3. not-found.tsx va 404 statusi

3.1 Kanondagi fayl

app/not-found.tsx — v1 dagi 404 sahifasi ning Next.js versiyasi: yo'l ko'rsatuvchi havolalar va «Orqaga» tugmasi.

tsx
import type { Metadata } from "next";
import Link from "next/link";
import { OrqagaTugmasi } from "@/komponentlar/OrqagaTugmasi";

export const metadata: Metadata = { title: "Sahifa topilmadi — Aziz Karimov" };

// v1 dagi 404.html (04/86): yo'l ko'rsatuvchi havolalar.
// 404 statusda Next `noindex` ni o'zi qo'shadi.
export default function TopilmadiSahifasi() {
  return (
    <main id="asosiy">
      <h1>Sahifa topilmadi</h1>
      <p>Manzil noto'g'ri yoki sahifa ko'chirilgan bo'lishi mumkin.</p>
      <ul>
        <li>
          <Link href="/">Bosh sahifa</Link>
        </li>
        <li>
          <Link href="/loyihalar">Loyihalar</Link>
        </li>
        <li>
          <Link href="/aloqa">Aloqa</Link>
        </li>
      </ul>
      <p>
        <OrqagaTugmasi />
      </p>
    </main>
  );
}

Kanondagi uzun izoh telefonga sig'ishi uchun ikki qatorga bo'lindi. metadata qatori kanonda aynan shunday (70 belgidan uzun). OrqagaTugmasi — router.back() chaqiradigan kichik client komponent, uni keyingi darsda ochamiz.

app/not-found.tsx ikki holatda chiziladi:

Holat Misol
Hech bir papkaga mos kelmagan manzil /yoq, /blog/eski
Sahifa notFound() chaqirdi /loyihalar/yoq

Birinchi holat faqat root darajadagi app/not-found.tsx bilan ishlaydi. Ichki papkadagi not-found.tsx (masalan app/loyihalar/not-found.tsx) faqat o'sha papka ichida notFound() chaqirilganda ko'rinadi.

3.2 [slug] da notFound()

Fayl-asosli routing darsidagi "Loyiha topilmadi" bloki endi bitta qator:

tsx
const { slug } = await params;
const loyiha = loyihaniTop(slug);
// notFound() — eng yaqin not-found.tsx ni ko'rsatadi
// va 404 qaytaradi (N-05)
if (!loyiha) notFound();
const cs = loyiha.caseStudy;

Biz next build + next start bilan tekshirdik (curl -D -, faqat kerakli sarlavhalar):

text
== /yoq
HTTP/1.1 404 Not Found
<meta name="robots" content="noindex"/>

404 statusi va noindex meta tegi — ikkalasi ham bor. noindex ni biz yozmadik: Next.js 404 sahifasiga uni o'zi qo'shadi. Google bunday sahifani indeksga olmaydi.

3.3 Biz topdik: noma'lum slug — birinchi so'rovda 200

Endi /loyihalar/yoq9 — [slug] papkasiga tushadigan, lekin ro'yxatda yo'q loyiha. Bir xil manzilni ikki marta so'radik:

text
== /loyihalar/yoq9
HTTP/1.1 200 OK
x-nextjs-postponed: 1
<meta name="robots" content="noindex"/>
== /loyihalar/yoq9
HTTP/1.1 404 Not Found
x-nextjs-cache: HIT
<meta name="robots" content="noindex"/>

Birinchi so'rov — 200, ikkinchisi — 404. Kanon xuddi shuni topgan: har yangi noma'lum slug'ning birinchi so'rovi 200, keyingilari 404.

Nega? Fayl-asosli routing darsidagi build jadvalini eslang: ◐ /loyihalar/[slug] — PPR qobig'i (qisman prerender). Noma'lum slug kelganda Next.js avval tayyor qobiqni oqim (streaming) bilan yubora boshlaydi. HTTP statusi esa javobning eng boshida, sarlavhalar bilan ketadi. Sahifa notFound() ga yetganda status allaqachon 200 deb yuborilgan — uni qaytarib bo'lmaydi.

Next.js hujjati buni ochiq yozadi: oqim boshlangach status 200 qoladi, shuning uchun Next.js HTML ichiga noindex qo'yadi. Google sahifani indekslamaydi — bu yaxshi. Lekin status baribir 200, ba'zi botlar va analitika vositalari uni "soft 404" deb belgilaydi.

Next 15 dagi eski yechim — export const dynamicParams = false ("ro'yxatdan boshqa slug yo'q"). Kanon uni sinadi:

text
Error: Route segment config "dynamicParams" is not compatible with `nextConfig.cacheComponents`. Please remove it.

Tarjimasi: "dynamicParams segment sozlamasi Cache Components bilan mos emas, olib tashlang". Kanon loading.tsx ni olib tashlab ham ko'rdi — natija o'zgarmadi: ◐ qobiq baribir oqim bilan ketadi.

Halol xulosa: hozircha Google uchun noindex yetarli, lekin status 200. Haqiqiy 404 ni oqim boshlanishidan oldin berish kerak — so'rov sahifaga yetmasdan. Buni proxy.ts darsida qilamiz.

Tekshirib ko'ring: /loyihalar/yoq va /yoq ning birinchi so'rovi qaysi statusni qaytaradi? Nega har xil?

Javob

/loyihalar/yoq — 200 (keyin 404), /yoq — darhol 404. /yoq hech qanday papkaga mos kelmaydi: Next.js oqim boshlamasdan 404 javobini beradi. /loyihalar/yoq esa [slug] qobig'iga tushadi, oqim boshlanadi, notFound() keyinroq chaqiriladi.

4. error.tsx — segment uchun xato chegarasi

4.1 Kanondagi fayl

tsx
"use client";

import { useEffect } from "react";

// Xato chegarasi faqat Client Component bo'la oladi (N-05).
// Prod'da server xatosining matni yashiriladi — faqat digest.
export default function XatoSahifasi({
  error,
  retry,
}: {
  error: Error & { digest?: string };
  retry: () => void;
}) {
  useEffect(() => {
    console.error(error);
  }, [error]);

  return (
    <main id="asosiy">
      <h1>Nimadir buzildi</h1>
      <p>Sahifani ko'rsatib bo'lmadi. Qayta urinib ko'ring.</p>
      {error.digest && <p className="ikkinchi">Xato kodi: {error.digest}</p>}
      <button type="button" onClick={() => retry()}>
        Qayta urinish
      </button>
    </main>
  );
}

Uchta qism:

Qism Nima
"use client" Fayl brauzerda ham ishlaydigan komponent — majburiy
error Ushlangan xato; digest — server xatosining kodi
retry "Qayta urinib ko'r" funksiyasi

4.2 Nega "use client" majburiy?

Error boundary darsidan eslang: React'da xato chegarasi — klass komponent, u getDerivedStateFromError bilan holat saqlaydi. Holat va onClick faqat brauzerda yashaydigan komponentda bo'ladi. Next.js'da sukut bo'yicha hamma komponent serverda ishlaydi, shuning uchun error.tsx ni brauzerga "ruxsat berish" kerak — "use client" qatori aynan shuni qiladi. To'liq ma'nosini Client Components darsida ochamiz.

Biz "use client" ni olib tashlab, build qildik (ranglar va kod parchasi olib tashlangan):

text
Error: Turbopack build failed with 2 errors:
./src/app/error.tsx:1:10
Error: You're importing a module that depends on `useEffect` into a React Server Component module. This API is only available in Client Components. To fix, mark the file (or its parent) with the `"use client"` directive.
./src/app/error.tsx:1:1
Error: src/app/error.tsx must be a Client Component. Add the "use client" directive the top of the file to resolve this issue.

Ikkinchi xato aniqroq: "src/app/error.tsx Client Component bo'lishi shart. Fayl boshiga "use client" direktivasini qo'shing". Birinchisi — useEffect ning oqibati: hook'lar serverda ishlamaydi. useEffect bo'lmasa ham, ikkinchi xato baribir chiqadi.

4.3 Biz sinadik: prod'da xato matni yashiriladi

error.tsx qanday ishlashini ko'rish uchun tajriba sahifasi yasadik. Unda GitHub blokini taqlid qiladigan komponent xato tashlaydi, va xato matnida "maxfiy" ma'lumot bor:

tsx
async function GithubBlok() {
  await connection(); // har so'rovda ishlasin (N-14)
  if (Date.now() > 0) {
    throw new Error("GitHub API javob bermadi (kalit: maxfiy-123)");
  }
  return <p>Profil</p>;
}

connection() va Date.now() > 0 — tajriba uchun hiyla: birinchisi build vaqtida ishlamasligi uchun (Rendering strategiyalari darsida), ikkinchisi TypeScript "funksiya hech narsa qaytarmaydi" demasligi uchun.

next build + next start, keyin headless Chrome'da sahifani ochdik. Ekranda:

text
Nimadir buzildi | Sahifani ko'rsatib bo'lmadi. Qayta urinib ko'ring. | Xato kodi: 2204450643 | Qayta urinish

Brauzer konsolida (useEffect dagi console.error):

text
Error: Minified React error #441; visit https://react.dev/errors/441 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.

Serverning terminalida esa:

text
⨯ Error: GitHub API javob bermadi (kalit: maxfiy-123)
    at e (C:\Users\…\.next\server\chunks\ssr\_0j0xk8vpm9llx._.js:30:15768) {
  digest: '2204450643'
}

Mana digest ning vazifasi. Brauzer xatoning asl matnini olmadi — HTML'da ham maxfiy-123 yo'q, faqat {"digest":"2204450643"}. Asl matn faqat server logida, va ikkalasini bir xil kod bog'laydi. Foydalanuvchi "Xato kodi: 2204450643" ni sizga yuborsa, siz logdan aynan shu xatoni topasiz.

#441 — React production build'idagi qisqartirilgan xato raqami. Havoladagi sahifa 2026-10 holatida ochilmaydi (404), shuning uchun to'liq matnni React manba kodidagi xato kodlari ro'yxatidan oldik (scripts/error-codes/codes.json): "An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error." — "Server Components renderida xato bo'ldi. Aniq matn production'da maxfiy ma'lumot sizib chiqmasligi uchun olib tashlangan. Xato obyektida digest xususiyati bor — u xato haqida qo'shimcha ma'lumot berishi mumkin".

next dev da esa o'sha sahifa brauzer konsoliga asl matnni chiqardi:

text
Error: GitHub API javob bermadi (kalit: maxfiy-123)

Dev — siz uchun, prod — foydalanuvchi uchun. Shuning uchun error.tsx da error.message ni ekranga chiqarmang: dev'da ko'rinadi, prod'da baribir umumiy matn bo'ladi. Client komponentda (brauzerda) tashlangan xatoning matni esa prod'da ham saqlanadi — u allaqachon brauzerda.

4.4 Status — 200

Tajriba sahifasining statusi — 200. Xato oqim boshlangandan keyin, <Suspense> ichida chiqdi — «Noma'lum slug — birinchi so'rovda 200» bo'limidagi sabab bilan bir xil. Xato sahifasini Google indekslamasligi uchun muhim sahifalarda xatoni oqimdan oldin tekshirish kerak. Portfolio uchun bu kichik masala: GitHub bloki yiqilsa, sahifaning qolgan qismi baribir foydali.

4.5 retry va reset

Next 16.4 da error.tsx ikki funksiya oladi:

Funksiya Nima qiladi
retry() Segmentni serverdan qayta oladi va qayta chizadi
reset() Faqat xato holatini tozalaydi, serverga so'rov yo'q

Hujjat ko'p hollarda retry() ni tavsiya qiladi. Xato vaqtinchalik bo'lsa (tarmoq uzildi, API band edi), yangi so'rov uni hal qilishi mumkin. reset() — eski kitob va maqolalardagi nom; u ma'lumotni qayta olmaydi, faqat xato chegarasini qayta chizadi. retry Next 16.2 da unstable_retry nomi bilan kirgan, 16.3 da barqaror bo'lgan (hujjatdagi versiyalar tarixi).

Bizning tajribada «Qayta urinish» bosilganda server yana xato tashladi, ekran o'zgarmadi — chunki xato doimiy edi. Haqiqiy vaqtinchalik xatoda ikkinchi urinish o'tishi mumkin.

4.6 Natija oynasida: error.tsx modeli

error.tsx ichida nima bo'layotganini oddiy React bilan qayta qurish mumkin — bu Error boundary darsidagi klass komponent. fallback o'rniga Next.js'dagidek funksiya beramiz: u error va retry ni oladi. retry holatni tozalaydi va bolani qayta chizadi.

tsx
import { Component, type ReactNode } from "react";

type Fallback = (p: {
  error: Error;
  retry: () => void;
}) => ReactNode;

class ErrorBoundary extends Component<
  { fallback: Fallback; children: ReactNode },
  { error: Error | null }
> {
  state = { error: null as Error | null };
  static getDerivedStateFromError(error: Error) {
    return { error };
  }
  retry = () => this.setState({ error: null });
  render() {
    const { error } = this.state;
    if (!error) return this.props.children;
    return this.props.fallback({ error, retry: this.retry });
  }
}

// "tarmoq": birinchi urinishda uzilgan, keyin tiklanadi
const network = { up: false };

function GithubBlock() {
  if (!network.up) throw new Error("GitHub API javob bermadi");
  return <p>Profil yuklandi</p>;
}

function ErrorPage({ error, retry }: Parameters<Fallback>[0]) {
  return (
    <>
      <h1>Nimadir buzildi</h1>
      <p>{error.message}</p>
      <button
        onClick={() => {
          network.up = true; // tarmoq tiklandi
          retry();
        }}
      >
        Qayta urinish
      </button>
    </>
  );
}

export default function App() {
  return (
    <ErrorBoundary fallback={(p) => <ErrorPage {...p} />}>
      <GithubBlock />
    </ErrorBoundary>
  );
}

Konsolda:

text
Error: GitHub API javob bermadi
The above error occurred in the <GithubBlock> component.
React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.

Ekranda:

text
Profil yuklandi

Birinchi chizishda GithubBlock xato tashladi, xato chegarasi ErrorPage ni ko'rsatdi. Konsoldagi uch qator — React'ning o'zi: ushlangan xatoni ham dev rejimda konsolga yozadi va qaysi xato chegarasi ushlaganini aytadi ("React bu daraxtni siz bergan ErrorBoundary chegarasi yordamida noldan qayta yaratadi"). «Qayta urinish» bosilgach "tarmoq tiklandi", retry holatni tozaladi, GithubBlock qayta chizildi va endi o'tdi. Haqiqiy retry() bundan bir qadam ko'p ishlaydi — serverdan yangi ma'lumot ham so'raydi.

E'tibor bering: bu modelda error.message ekranga chiqdi, chunki xato brauzerda tashlandi. Server xatosida prod'da u yerda umumiy matn bo'lardi.

Tekshirib ko'ring: foydalanuvchi «Saqlash» tugmasini bosdi va onClick ichida xato chiqdi. error.tsx uni ushlaydimi?

Javob

Yo'q. Xato chegarasi faqat chizish (render) paytidagi xatolarni ushlaydi — Error boundary darsidagi qoida. Hodisa ichidagi xatoni try/catch bilan o'zingiz ushlaysiz va holat orqali ko'rsatasiz.

5. global-error.tsx — root layout yiqilganda

app/error.tsx root layout'ning ichida turadi (ierarxiya rasmini eslang). Root layout'ning o'zida xato bo'lsa, uni ushlaydigan hech kim yo'q. Shu holat uchun app/global-error.tsx:

tsx
"use client";

// Root layout'ning o'zi yiqilganda — o'z <html> va <body> si
// bilan (N-05). globals.css bu yerda yo'q, shuning uchun oddiy.
export default function GlobalXato({
  retry,
}: {
  error: Error & { digest?: string };
  retry: () => void;
}) {
  return (
    <html lang="uz">
      <body>
        <main>
          <h1>Sayt vaqtincha ishlamayapti</h1>
          <button type="button" onClick={() => retry()}>
            Qayta urinish
          </button>
        </main>
      </body>
    </html>
  );
}

Uch farq:

  • O'z <html> va <body> si. U root layout'ning o'rniga chiziladi — root layout yo'q, demak Layout va template darsidagi qoida bo'yicha bu teglarni kim yozadi? Faqat o'zi.
  • globals.css yo'q. Sayt stillari root layout'da ulangan, u esa yiqilgan. Kanon sahifani ataylab oddiy qoldirdi.
  • metadata eksporti ishlamaydi — fayl client komponent. Sarlavha kerak bo'lsa, <title> tegini to'g'ridan JSX ichida yozish mumkin.

global-error.tsx kamdan-kam ko'rinadi. Lekin u bo'lmasa, root layout xatosida foydalanuvchi Next.js'ning inglizcha standart sahifasini ko'radi.

6. loading.tsx — avtomatik Suspense

6.1 Kanondagi fayl

tsx
// loading.tsx — sahifa atrofida avtomatik <Suspense> (N-05).
// Faqat build vaqtida yaratilmagan slug'da ko'rinadi.
export default function LoyihaYuklanmoqda() {
  return (
    <main id="asosiy" aria-busy="true">
      <h1>Loyiha yuklanmoqda…</h1>
    </main>
  );
}

aria-busy="true" — ekran o'quvchiga "bu qism hali tayyorlanmoqda" degan signal. loading.tsx — oddiy Server Component, "use client" shart emas.

6.2 Qachon ko'rinadi?

Kanon izohidagi gapga e'tibor bering: "faqat build vaqtida yaratilmagan slug'da". /loyihalar/vazifalar — ○ statik, HTML tayyor, kutadigan narsa yo'q. Suspense fallback'i bir lahza ham chiqmaydi.

/loyihalar/yoq9 kabi noma'lum slug'da esa sahifa ◐ qobiqdan chiziladi. Qobiqning bir qismi aynan shu loading.tsx: Next.js uni build vaqtida tayyorlab qo'yadi va so'rov kelganda darhol yuboradi. Sahifaning o'zi tayyor bo'lgach, fallback almashadi.

Navigatsiyada yana bir foyda bor. <Link> sahifani oldindan yuklaganda (prefetch, Navigatsiya darsida), dinamik sahifa uchun loading.tsx gacha bo'lgan qismni oladi. Bosish bilanoq ekran o'zgaradi — foydalanuvchi "bosdim, hech narsa bo'lmadi" deb qolmaydi.

6.3 Natija oynasida: loading.tsx = Suspense

loading.tsx ning ishi — Suspense darsidagi fallback. Promise'ni use() bilan o'qiydigan sahifa va uning atrofida Next.js qo'yadigan Suspense chegarasi:

tsx
import { Suspense, use } from "react";

type Project = { name: string };

const projectPromise = new Promise<Project>((resolve) =>
  setTimeout(() => resolve({ name: "Vazifalar ilovasi" }), 400),
);

// app/loyihalar/[slug]/page.tsx o'rnida
function ProjectPage() {
  const project = use(projectPromise);
  return <h1>{project.name}</h1>;
}

// app/loyihalar/[slug]/loading.tsx o'rnida
function Loading() {
  return <h1>Loyiha yuklanmoqda…</h1>;
}

export default function App() {
  return (
    <Suspense fallback={<Loading />}>
      <ProjectPage />
    </Suspense>
  );
}

Ekranda:

text
Vazifalar ilovasi

ekran("Loyiha yuklanmoqda") qadami oraliq holatni tekshiradi: avval fallback, 400 ms dan keyin sahifa. Next.js'da <Suspense> ni siz yozmaysiz — loading.tsx faylining o'zi shu.

Bir farq bor. Bu yerda promise brauzerda kutilyapti. Next.js'da sahifa serverda kutadi, fallback HTML'ning birinchi bo'lagida ketadi, sahifa esa keyingi bo'lakda keladi. Bu oqimni Streaming va Suspense darsida o'lchaymiz.

Tekshirib ko'ring: app/loading.tsx (root'da) qo'ysangiz, u qaysi sahifalarga ta'sir qiladi?

Javob

Hammasiga: root segmentdagi Suspense butun app/ ni o'raydi. Lekin statik sahifalarda u baribir ko'rinmaydi — kutish yo'q. Odatda loading.tsx ni aniq sekin bo'lishi mumkin bo'lgan segmentga qo'yish yaxshiroq: shunda layout'ning qolgan qismi (menyu) darhol ko'rinadi.

7. Boshqa maxsus fayllar

7.1 forbidden.tsx va unauthorized.tsx

notFound() ning ikki aka-ukasi bor: forbidden() (403 — "ruxsat yo'q") va unauthorized() (401 — "avval kiring"). Ularning UI fayli — forbidden.tsx va unauthorized.tsx. Ular hali eksperimental: next.config.ts da experimental.authInterrupts: true yoqilishi kerak (hujjat, 2026-10-21). Kanonda kirish (login) yo'q, shuning uchun ular ishlatilmagan.

tsx
// next.config.ts: experimental: { authInterrupts: true }
import { forbidden } from "next/navigation";

export default async function AdminSahifasi() {
  const foydalanuvchi = await joriyFoydalanuvchi(); // 28-qismda
  if (foydalanuvchi.rol !== "admin") forbidden();
  return <main>…</main>;
}

Status qoidasi notFound() bilan bir xil: oqim boshlanmagan bo'lsa — 403/401, boshlangan bo'lsa — 200 + noindex. Haqiqiy kirish tizimi — 28-qismda; hozir faqat bunday fayllar borligini bilish yetarli.

7.2 Qolganlari — xarita

app/ da yana bir nechta maxsus nom bor. Hammasi keyingi darslarda:

Fayl Nima Dars
default.tsx Parallel slot uchun zaxira Parallel routes
route.ts Sahifa emas, API manzil Route Handlers
icon.svg, opengraph-image.tsx Favicon, ulashish rasmi SEO fayllari
sitemap.ts, robots.ts Qidiruv tizimlari uchun SEO fayllari
src/proxy.ts Har so'rov oldidan ishlaydi proxy.ts
src/instrumentation.ts Server ishga tushganda, xatolar logi Xatolar va loglar

icon.svg ni Layout va template darsida qo'shgandik — u ham maxsus fayl.

8. Portfolio qadami: xato va topilmadi sahifalari

Bu dars va keyingi dars portfolio ning bitta holatini (06) quradi. Commit hali qilmang — u keyingi darsda, navigatsiya bilan birga.

8.1 Fayllar

Fayl Nima
app/not-found.tsx v1 404: havolalar, «Orqaga» tugmasi, main#asosiy
app/error.tsx Client; «Nimadir buzildi», digest, retry()
app/global-error.tsx O'z <html>/<body>, oddiy
app/loyihalar/[slug]/loading.tsx aria-busy="true"
app/loyihalar/[slug]/page.tsx "Loyiha topilmadi" bloki o'rniga notFound()

8.2 Kanon o'lchovi (holat 06)

Sahifa Oldin (holat 04) Keyin (holat 06)
/yoq 404, axe 3 404, axe 0
/loyihalar/yoq 200, "Loyiha topilmadi" 200 (1-so'rov), keyin 404, noindex
Build jadvali — o'zgarmadi

axe 3 → 0: Next.js'ning standart 404 sahifasida main yo'q edi, bizniki — main#asosiy bilan. Lint, tip, format — 0, hydration ogohlantirishi — 0.

9. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
… must be a Client Component error.tsx da "use client" yo'q Fayl boshiga "use client"
404 o'rniga 500 yoki xato sahifasi notFound() try/catch ichida try dan tashqarida chaqiring
Root layout xatosida inglizcha sahifa global-error.tsx yo'q Uni yozing (o'z <html> bilan)
global-error stilsiz globals.css root layout'da Kerakli stilni o'zida bering
error.message prod'da umumiy matn Server xatosi yashiriladi digest ni ko'rsating, logdan qidiring
loading.tsx hech ko'rinmaydi Sahifa statik (○) Bu normal — kutish yo'q
Noma'lum slug 200 qaytaradi Oqim boshlangach status o'zgarmaydi noindex bor; to'liq yechim — proxy.ts
dynamicParams … not compatible Next 15 usuli Cache Components bilan Olib tashlang
Ichki not-found.tsx /yoq da ishlamaydi Mos kelmagan manzil faqat root'dagisini oladi app/not-found.tsx yozing

10. Mashqlar

Mashqlar kurs/mashqlar/23/05-maxsus-fayllar/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.

1-mashq (oson): qaysi fayl?

  • Server xatosida "Nimadir buzildi" va «Qayta urinish» —
  • /blog/eski-maqola — bunday papka yo'q —
  • Root layout'dagi xato —
  • Sekin sahifa ochilguncha skelet —
  • Kirmagan foydalanuvchiga 401 —
Yechim
  • error.tsx — segment uchun xato chegarasi.
  • not-found.tsx — root'dagisi; mos kelmagan manzil uchun boshqa variant yo'q.
  • global-error.tsx — error.tsx root layout ichida turadi, uni ushlay olmaydi.
  • loading.tsx — avtomatik Suspense fallback'i.
  • unauthorized.tsx — unauthorized() chaqirilganda (eksperimental, authInterrupts).

2-mashq (o'rta): ierarxiyani chizing

Funksiya yozing: wrapSegment(files) — segmentdagi fayllar ro'yxatini oladi (["page", "loading", "layout"] kabi, tartibsiz) va ular qanday o'ralishini satr qilib qaytaradi: "layout > loading > page". Tartib — «Qaysi fayl nimani o'raydi» bo'limidagi ierarxiya: layout, template, error, loading, not-found, page. Ro'yxatda yo'q fayl o'tkazib yuboriladi. Ishora: tartib massivini filter qiling va includes bilan tekshiring, keyin join(" > ").

Sinov: ["page", "loading", "layout"], ["error", "page", "template", "not-found"], ["page"].

Yechim
js
const ORDER = [
  "layout",
  "template",
  "error",
  "loading",
  "not-found",
  "page",
];

function wrapSegment(files) {
  return ORDER.filter((name) => files.includes(name)).join(" > ");
}

console.log(wrapSegment(["page", "loading", "layout"]));
console.log(wrapSegment(["error", "page", "template", "not-found"]));
console.log(wrapSegment(["page"]));

Konsolda:

text
layout > loading > page
template > error > not-found > page
page

Kirish tartibi muhim emas — natijani ORDER belgilaydi. Next.js ham xuddi shunday: fayllarni qaysi tartibda yaratganingiz ahamiyatsiz, o'rash tartibi doim bir xil.

3-mashq (qiyin): notFound va xatoni ajratadigan xato chegarasi

«error.tsx modeli» blokini kengaytiring: RouteBoundary xatoning digest iga qarasin. digest === "NEXT_HTTP_ERROR_FALLBACK;404" bo'lsa — <h1>Sahifa topilmadi</h1>, aks holda — «Nimadir buzildi» va «Qayta urinish». Sahifa: ProjectPage({ slug }) — slug ro'yxatda (["vazifalar", "bahor"]) bo'lmasa notFound() chaqiradi (next/navigation dan). App da ikkita tugma: «bahor» va «yoq» — bosilganda slug o'zgaradi. Xato chegarasi yangi slug'da qaytadan boshlashi uchun unga key={slug} bering (key bilan reset).

Yechim
tsx
import { Component, useState, type ReactNode } from "react";
import { notFound } from "next/navigation";

const NOT_FOUND = "NEXT_HTTP_ERROR_FALLBACK;404";
type RouteError = Error & { digest?: string };

class RouteBoundary extends Component<
  { children: ReactNode },
  { error: RouteError | null }
> {
  state = { error: null as RouteError | null };
  static getDerivedStateFromError(error: RouteError) {
    return { error };
  }
  render() {
    const { error } = this.state;
    if (!error) return this.props.children;
    if (error.digest === NOT_FOUND) return <h1>Sahifa topilmadi</h1>;
    return (
      <>
        <h1>Nimadir buzildi</h1>
        <button onClick={() => this.setState({ error: null })}>
          Qayta urinish
        </button>
      </>
    );
  }
}

const SLUGS = ["vazifalar", "bahor"];

function ProjectPage({ slug }: { slug: string }) {
  if (!SLUGS.includes(slug)) notFound();
  return <h1>Loyiha: {slug}</h1>;
}

export default function App() {
  const [slug, setSlug] = useState("vazifalar");
  return (
    <>
      <button onClick={() => setSlug("bahor")}>bahor</button>{" "}
      <button onClick={() => setSlug("yoq")}>yoq</button>
      <RouteBoundary key={slug}>
        <ProjectPage slug={slug} />
      </RouteBoundary>
    </>
  );
}

Konsolda:

text
Error: NEXT_HTTP_ERROR_FALLBACK;404
The above error occurred in the <ProjectPage> component.
React will try to recreate this component tree from scratch using the error boundary you provided, RouteBoundary.

Ekranda:

text
bahor yoq
Loyiha: bahor

«yoq» bosilganda notFound() xato tashladi, xato chegarasi uning digest ini tanidi va "Sahifa topilmadi" ni ko'rsatdi (ekran(…) qadami tekshiradi). Konsoldagi qatorlar — React'ning ushlangan xato haqidagi yozuvi: xato ProjectPage da chiqdi, RouteBoundary ushladi. «bahor» bosilganda key o'zgardi — xato chegarasi yangidan yaratildi, xato holati yo'qoldi. Next.js ham ichida xatoni shu digest bo'yicha ajratadi: biri not-found.tsx ga, qolgani error.tsx ga.

4-mashq: Portfolio qadami

O'z portfolio ingizga not-found.tsx (v1 dagi 404 havolalari bilan), error.tsx, global-error.tsx va loyihalar/[slug]/loading.tsx qo'shing. [slug] sahifasida "topilmadi" blokini notFound() bilan almashtiring. Tekshiring: npm run build, npm start, keyin curl -I http://localhost:3000/yoq — 404. /loyihalar/yoq ni ikki marta so'rang va statuslarni solishtiring.

Yechim

Namuna — «Portfolio qadami» bo'limidagi fayllar jadvali. Kod — «not-found.tsx va 404 statusi» bo'limida. /loyihalar/yoq ning birinchi so'rovi 200, ikkinchisi 404 bo'lsa — bu siz xato qilgansiz degani emas, kanon ham shuni ko'rgan. curl chiqishida x-nextjs-postponed: 1 — oqim bilan ketgan javob belgisi. Commit hali qilmang: keyingi darsda navigatsiya bilan birga bo'ladi.

11. Real ishda

  • Har Next.js loyihada kamida not-found.tsx va error.tsx bo'ladi. Ular bo'lmasa, foydalanuvchi inglizcha standart sahifani ko'radi — mahalliy saytda bu darhol "chala ish" bo'lib ko'rinadi.
  • digest va loglar. Katta loyihalarda xato kuzatish xizmati (Sentry kabi) server xatosini digest bilan saqlaydi. Qo'llab-quvvatlash xodimi foydalanuvchidan kodni so'raydi — xuddi bankdagi "operatsiya raqami" kabi.
  • Soft 404 va SEO. Do'konda o'chirilgan mahsulot sahifasi 200 qaytarsa, Google Search Console'da "Soft 404" ogohlantirishi chiqadi. Next.js'dagi oqim va status munosabatini bilish shu muammoni tez topishga yordam beradi.
  • Intervyu savoli: "error.tsx nega client komponent?" va "root layout xatosini qaysi fayl ushlaydi?" — endi ikkalasiga javob bilasiz.

Xulosa

  • Maxsus fayl nomlari React o'rovchilarini avtomatik qo'yadi: error.tsx — xato chegarasi (error boundary), loading.tsx — Suspense, not-found.tsx — 404 UI.
  • Tartib: layout → template → error → loading → not-found → page; error.tsx o'z segmentidagi layout'ni ushlamaydi.
  • notFound() xato tashlaydi (digest bilan) — try/catch ga o'ramang; 404 da Next noindex ni o'zi qo'shadi.
  • error.tsx — client komponent; prod'da server xatosi matni yashiriladi, digest server logi bilan bog'laydi; retry() qayta oladi.
  • global-error.tsx root layout o'rniga, o'z <html>/<body> si bilan chiziladi.
  • Oqim boshlangach status o'zgarmaydi: noma'lum slug birinchi so'rovda 200 — yechim proxy.ts da.

Keyingi dars: Navigatsiya: Link, useRouter va URL hooklari — menyudagi joriy havola, URL'dagi teg filtri va «Orqaga» tugmasi.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Next.js maxsus fayllari: loading.tsx, error.tsx, not-found.tsx va boshqalar — IlmHamroh