page.tsx, layout.tsx, loading.tsx, error.tsx, not-found.tsx — har birining roli
Muammodan boshlaylik
Siz React da sahifa yozyapsiz. Ma'lumot yuklanayotganda spinner ko'rsatish kerak. Xato bo'lganda error xabar ko'rsatish kerak. Sahifa topilmasa 404 ko'rsatish kerak.
Bularning hammasi uchun qo'lda kod yozasiz — har bir sahifada takrorlanadi:
// React — har bir sahifada shu pattern takrorlanadi
function Page() {
const [data, setData] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
useEffect(() => {
fetch('/api/data')
.then(r => r.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false))
}, [])
if (loading) return <Spinner />
if (error) return <ErrorMessage error={error} />
return <div>{data.title}</div>
}
10 ta sahifangiz bo'lsa — 10 ta joyda shu pattern. Next.js App Router da bu muammo yo'q. Har bir holat uchun alohida fayl bor — bir marta yozasiz, avtomatik ishlaydi.
5 ta maxsus fayl
app/dashboard/
├── page.tsx ← asosiy kontent
├── layout.tsx ← qolip (sidebar, navbar)
├── loading.tsx ← yuklanayotganda
├── error.tsx ← xato bo'lganda
└── not-found.tsx ← sahifa topilmaganda
Bularning har biri qachon va qanday ishlashini ko'ramiz.
page.tsx — sahifaning o'zi
Bu fayl yo'q bo'lsa — papka route sifatida tanilmaydi. page.tsx — sahifaning asosiy kontenti.
// app/dashboard/page.tsx
export default async function DashboardPage() {
const stats = await fetch('https://api.example.com/stats').then(r => r.json())
return (
<div>
<h1>Dashboard</h1>
<p>Foydalanuvchilar: {stats.users}</p>
</div>
)
}
Server Component bo'lgani uchun async/await to'g'ridan-to'g'ri ishlatiladi. Ma'lumot yuklanib bo'lguncha Next.js loading.tsx ni ko'rsatadi.
layout.tsx — qolip
Sahifani o'rab turadigan qolip. Sahifa o'zgarganda layout qayta render bo'lmaydi — faqat {children} yangilanadi.
Tasavvur qiling: telefon ilovasi. Pastki navigatsiya bar har sahifada ko'rinadi. Sahifalar o'zgarganda faqat kontent o'zgaradi, navigatsiya qoladi. Aynan shu — layout.
// app/dashboard/layout.tsx
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<div className="flex">
<aside>
<a href="/dashboard">Asosiy</a>
<a href="/dashboard/users">Foydalanuvchilar</a>
<a href="/dashboard/settings">Sozlamalar</a>
</aside>
<main className="flex-1">
{children}
</main>
</div>
)
}
/dashboard dan /dashboard/settings ga o'tganda — sidebar qayta render bo'lmaydi, faqat {children} o'rnidagi kontent o'zgaradi. Bu performance uchun muhim.
Layout qatlamlari:
app/layout.tsx ← barcha sahifalar uchun
app/dashboard/layout.tsx ← faqat /dashboard/* uchun
app/dashboard/settings/layout.tsx ← faqat /dashboard/settings/* uchun
Har bir layout o'z farzandlarini o'rab turadi. Ichki layout tashqi layoutni bekor qilmaydi — ular bir-birining ustiga qo'shiladi.
loading.tsx — yuklanish holati
page.tsx ma'lumot yuklab bo'lguncha Next.js loading.tsx ni ko'rsatadi. Siz hech qanday useState yoki useEffect yozmasangiz ham — avtomatik ishlaydi.
Bu React Suspense ustiga qurilgan. Next.js page.tsx ni Suspense bilan o'raydi, loading.tsx esa fallback sifatida ko'rsatiladi.
// app/dashboard/loading.tsx
export default function Loading() {
return (
<div>
{/* Oddiy matn */}
<p>Yuklanmoqda...</p>
{/* Yoki skeleton UI */}
<div className="animate-pulse">
<div className="h-8 bg-gray-200 rounded mb-4" />
<div className="h-4 bg-gray-200 rounded w-3/4" />
</div>
</div>
)
}
💡 Skeleton UI — yuklanayotganda kontent shakliga o'xshash kulrang bloklar ko'rsatish. Foydalanuvchi "nimadir yuklanmoqda" deb tushunadi va sahifa "bo'sh" ko'rinmaydi. YouTube, LinkedIn, Facebook — barchasi skeleton ishlatadi.
Muhim: loading.tsx faqat server tomonidagi yuklanishni qoplaydi — ya'ni page.tsx dagi async funksiya tugaguncha. Client Component dagi useEffect fetch uchun alohida loading holati kerak bo'ladi.
error.tsx — xato holati
page.tsx da xato yuz bersa — Next.js error.tsx ni ko'rsatadi. Bu fayl Client Component bo'lishi shart — chunki reset funksiyasi brauzerda ishlaydi.
// app/dashboard/error.tsx
'use client'
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. Masalan, 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.
error.tsx qaysi xatolarni tutadi?
Faqat o'sha papka va uning farzandlaridagi xatolarni. app/dashboard/error.tsx — /dashboard/* sahifalaridagi xatolarni tutadi. Root darajadagi xatolar uchun app/error.tsx kerak.
Layout dagi xatolarni error.tsx tutmaydi — chunki error.tsx layout ichida joylashadi. Layout xatosi uchun yuqori darajadagi error.tsx kerak.
not-found.tsx — 404 holati
Ikki xil holat bor:
1. Mavjud bo'lmagan URL — foydalanuvchi /dashboard/xyz ga kiradi, bunday route yo'q. Next.js avtomatik not-found.tsx ko'rsatadi.
2. Kod ichida notFound() chaqirish — route mavjud, lekin ma'lumot topilmadi:
// app/dashboard/users/[id]/page.tsx
import { notFound } from 'next/navigation'
export default async function UserPage({ params }) {
const { id } = await params
const user = await fetch(`/api/users/${id}`).then(r => r.json())
if (!user) notFound() // ← 404 sahifasiga yo'naltiradi
return <h1>{user.name}</h1>
}
// app/dashboard/not-found.tsx
import Link from 'next/link'
export default function NotFound() {
return (
<div>
<h2>Sahifa topilmadi</h2>
<Link href="/dashboard">Dashboard ga qaytish</Link>
</div>
)
}
app/not-found.tsx — butun ilova uchun global 404. app/dashboard/not-found.tsx — faqat dashboard ichidagi 404 uchun.
Barchasi birgalikda qanday ishlaydi
/dashboard/users/42 ga kirganda Next.js quyidagi tartibda ishlaydi:
1. Route topildi: app/dashboard/users/[id]/page.tsx
↓
2. Layout lar qo'llanadi:
app/layout.tsx → app/dashboard/layout.tsx
↓
3. loading.tsx ko'rsatiladi (page.tsx yuklanayotganda)
↓
4a. Muvaffaqiyatli → page.tsx kontenti ko'rsatiladi
4b. notFound() → not-found.tsx ko'rsatiladi
4c. Xato → error.tsx ko'rsatiladi
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>
}
Xato: Event handlers cannot be passed to Client Component props.
// ✅
'use client'
export default function Error({ reset }) {
return <button onClick={reset}>Qayta</button>
}
2. loading.tsx ni Client Component qilish
loading.tsx Server Component bo'lishi kerak — 'use client' qo'shish shart emas va qo'shmaslik yaxshiroq. Agar useState kerak bo'lsa — alohida komponent yarating.
3. Layout da ma'lumot olish va xato bo'lganda error.tsx ishlamaslik
// app/dashboard/layout.tsx
export default async function Layout({ children }) {
const data = await fetch('/api/data').then(r => r.json())
// Bu yerda xato bo'lsa — app/dashboard/error.tsx ISHLAMAYDI
// Yuqori darajadagi error.tsx kerak
}
Layout xatosi uchun app/error.tsx yoki app/dashboard/../error.tsx kerak.
Xulosa
page.tsx → sahifaning asosiy kontenti
layout.tsx → qolip, sahifalar o'zgarganda qayta render bo'lmaydi
loading.tsx → page.tsx yuklanayotganda avtomatik ko'rsatiladi
error.tsx → xato bo'lganda, 'use client' shart, reset funksiyasi bor
not-found.tsx → notFound() chaqirilganda yoki mavjud bo'lmagan URL da
Bularni bir marta yozasiz — Next.js qolganini o'zi hal qiladi.
Keyingi dars
6-dars: Link komponenti va useRouter — navigatsiya, prefetching
Sahifalar orasida qanday o'tish kerak, <a> tegi o'rniga nima ishlatiladi va prefetching nima uchun muhim.