Next.js ko'p yillar davomida React asosidagi loyihalar uchun eng mashhur frameworklardan biri bo'lib kelgan, ammo uning 13-versiyasidan boshlab joriy etilgan App Router butun arxitekturani tubdan o'zgartirdi. Agar siz ilgari Pages Router bilan ishlagan bo'lsangiz, App Router boshida g'alati tuyulishi mumkin, chunki u nafaqat papkalar tuzilishini, balki ma'lumotlarni yuklash va sahifani render qilish falsafasini ham qaytadan ko'rib chiqadi. Ushbu maqolada biz App Router'ning asosiy g'oyalarini, eski yondashuvdan farqini va har bir imkoniyatni real kod misollari orqali batafsil ko'rib chiqamiz, shunda siz o'z loyihangizda qaysi yondashuvni tanlashni aniq tushunasiz.
Pages Router va App Router o'rtasidagi tub farq
Eski Pages Router'da har bir fayl pages papkasida joylashgan va u to'g'ridan-to'g'ri brauzerda ishlaydigan komponentga aylanardi. Ma'lumotlarni yuklash uchun siz getServerSideProps yoki getStaticProps kabi maxsus funksiyalarni eksport qilishingiz kerak edi, bu esa komponent mantig'i bilan ma'lumot mantig'ini sun'iy ravishda ajratib qo'yardi. App Router esa app papkasiga asoslanadi va bu yerda komponentlar standart holatda Server Components hisoblanadi, ya'ni ular faqat serverda ishlaydi va brauzerga JavaScript yubormaydi. Bu farq juda muhim, chunki u sahifaning yuklanish tezligiga, SEO ko'rsatkichlariga va umumiy foydalanuvchi tajribasiga bevosita ta'sir qiladi.
App Router'ning yana bir kuchli tomoni shundaki, u layout, loading va error holatlarini fayl tizimi orqali tabiiy ravishda boshqarishga imkon beradi. Pages Router'da bunday holatlarni qo'lda boshqarish kerak edi, App Router esa maxsus nomlanган fayllar yordamida ularni avtomatik ravishda ushlab oladi. Quyida biz ushbu mexanizmlarning har birini alohida ko'rib chiqamiz.
Server Components — standart holatdagi yangi yondashuv
App Router'da yaratilgan har qanday komponent agar siz aniq belgilamasangiz, Server Component hisoblanadi. Bu degani komponent serverda render qilinadi, undagi kod brauzerga umuman yetib bormaydi, natijada ilovaning JavaScript hajmi sezilarli darajada kamayadi. Server Components ma'lumotlar bazasiga to'g'ridan-to'g'ri murojaat qila oladi, maxfiy API kalitlardan foydalanishi mumkin va og'ir kutubxonalarni mijoz brauzerига yuklamasdan ishlatishi mumkin. Agar sizga interaktivlik, ya'ni useState, useEffect yoki hodisalarni eshitish kerak bo'lsa, faylning eng yuqorisiga 'use client' direktivasini qo'shasiz va u Client Component'ga aylanadi.
// app/products/page.tsx — bu Server Component (standart)
async function getProducts() {
const res = await fetch('https://api.example.com/products')
return res.json()
}
export default async function ProductsPage() {
const products = await getProducts()
return (
<ul>
{products.map((p) => (
<li key={p.id}>{p.name}</li>
))}
</ul>
)
}Yuqoridagi misolda komponentning o'zi async ekanligiga e'tibor bering. Bu App Router'ning eng yoqimli xususiyatlaridan biri: Server Component to'g'ridan-to'g'ri asinxron bo'lishi va await ishlatishi mumkin. Sizga endi alohida data fetching funksiyalari kerak emas, ma'lumotni to'g'ridan-to'g'ri komponent ichida yuklaysiz va bu kod hech qachon brauzerga yetib bormaydi.
Fayl asosidagi marshrutlash: page va layout
App Router'da marshrut har bir papka orqali aniqlanadi va papka ichidagi page.tsx fayli o'sha marshrutning haqiqiy sahifasini ifodalaydi. Masalan app/blog/page.tsx fayli /blog manziliga, app/blog/[slug]/page.tsx esa dinamik /blog/biror-maqola manziliga mos keladi. Bundan tashqari layout.tsx fayli o'zining papkasidagi va undan pastdagi barcha sahifalar uchun umumiy o'ramni ta'minlaydi, masalan navigatsiya paneli yoki footer. Layout sahifalar almashganda qayta render qilinmaydi, bu esa holatni saqlab qolish va ishlash unumdorligini oshirish nuqtai nazaridan juda foydali.
// app/blog/layout.tsx
export default function BlogLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<section>
<nav>Blog navigatsiyasi</nav>
{children}
</section>
)
}Ushbu tuzilma tufayli ilovaning umumiy karkasi va sahifaga xos qism aniq ajratiladi. Layoutlar bir-birining ichiga joylashishi mumkin, ya'ni ildiz layout butun ilovani o'rab oladi, undan keyin har bir bo'lim o'z layoutiga ega bo'lishi mumkin va bu juda moslashuvchan iyerarxiyani vujudga keltiradi. Bu fayl asosidagi yondashuv yuklanish va xato holatlarini boshqarishda ham davom etadi.
App Router ma'lumotlar yuklanayotgan paytda foydalanuvchiga nimadir ko'rsatish uchun maxsus loading.tsx faylini taklif qiladi. Siz shunchaki papkaga shu nomdagi fayl qo'shasiz va Next.js u yerdagi sahifa ma'lumot kutayotган paytda avtomatik ravishda yuklanish holatini ko'rsatadi. Xuddi shunday error.tsx fayli render paytida xato yuz berganda ishga tushadi va u albatta Client Component bo'lishi kerak, chunki u xatoni qayta urinish imkoniyati bilan ushlab oladi.
// app/dashboard/loading.tsx
export default function Loading() {
return <p>Ma'lumotlar yuklanmoqda...</p>
}
// app/dashboard/error.tsx
'use client'
export default function Error({
error,
reset,
}: {
error: Error
reset: () => void
}) {
return (
<div>
<p>Xatolik yuz berdi: {error.message}</p>
<button onClick={() => reset()}>Qayta urinish</button>
</div>
)
}Bu mexanizm React'ning Suspense va Error Boundary konsepsiyalariga asoslanadi, ammo App Router ularni fayl tizimi orqali avtomatik o'rab beradi. Natijada siz boilerplate kodni yozmasdan, faqat tegishli fayllarni yaratish orqali professional yuklanish va xato tajribasini olasiz.
Server Actions — formalar va mutatsiyalar
Server Actions App Router'ning eng inqilobiy imkoniyatlaridan biri bo'lib, u serverda ishlaydigan funksiyalarni to'g'ridan-to'g'ri komponent ichidan chaqirishga imkon beradi, alohida API endpoint yaratmasdan. Siz funksiyaning yuqorisiga 'use server' direktivasini qo'yasiz va uni forma orqali yoki tugma bosilishida ishga tushirasiz. Bu ma'lumotlarni saqlash, yangilash yoki o'chirish uchun ajoyib, chunki barcha mantiq serverda qoladi va mijoz tarafiga ortiqcha kod yuborilmaydi.
// app/contact/page.tsx
export default function ContactPage() {
async function submit(formData: FormData) {
'use server'
const name = formData.get('name')
await saveToDatabase({ name })
}
return (
<form action={submit}>
<input name="name" />
<button type="submit">Yuborish</button>
</form>
)
}Bu yondashuv frontend va backend o'rtasidagi chegarani ancha silliqlashtiradi. Endi siz REST yoki GraphQL endpointlarni qo'lda yozish, fetch chaqiruvlarini boshqarish va xatolarni qayta-qayta ishlash bilan ovora bo'lmaysiz, balki shunchaki server funksiyasini yozasiz va uni forma bilan bog'laysiz.
Render strategiyalari: SSR, SSG va ISR
App Router uchta asosiy render strategiyasini qo'llab-quvvatlaydi va ularni tanlash sizning ma'lumotlaringiz qanchalik tez-tez o'zgarishiga bog'liq. Static Site Generation (SSG) sahifani qurish paytida bir marta yaratadi va u eng tez ishlaydi, blog yoki hujjatlar uchun ideal. Server-Side Rendering (SSR) esa har bir so'rovda sahifani serverda qaytadan render qiladi, bu doimo yangi ma'lumot talab qilinadigan holatlar uchun mos keladi. Incremental Static Regeneration (ISR) ikkalasining o'rtasini topadi: sahifa statik tarzda yaratiladi, ammo belgilangan vaqt o'tgach fon rejimида yangilanadi.
// SSG — standart, fetch keshlanadi
await fetch('https://api.example.com/data')
// SSR — har so'rovda yangi
await fetch(url, { cache: 'no-store' })
// ISR — har 60 soniyada yangilanadi
await fetch(url, { next: { revalidate: 60 } })Ko'rib turganingizdek, App Router'da render strategiyasi fetch chaqiruvining sozlamalari orqali boshqariladi, bu juda nozik va aniq nazoratni beradi. Siz hatto bir sahifaning ichida ba'zi ma'lumotlarni statik, boshqalarini esa dinamik qilib olishingiz mumkin, bu esa ilgari Pages Router'da deyarli imkonsiz edi. Umuman olganda App Router zamonaviy veb-ilovalar uchun kuchli, moslashuvchan va unumdor asos bo'lib, uni o'rganishga sarflangan vaqt albatta o'zini oqlaydi. Agar siz yangi loyiha boshlayotgan bo'lsangiz, App Router'ni tanlash uzoq muddatda eng to'g'ri qaror bo'ladi.