
Next.js 15+ da navigatsiya qanday ishlaydi - Prefetching, Streaming, Client-side Transitions, useLinkStatus va History API
Next.js App Router - Linking va Navigatsiya
Next.js da sahifalar serverda renderlanadi. Bu degani - yangi sahifani ko'rsatish uchun client server javobini kutishi kerak. Lekin Next.js buni sezilmas darajada tez qiladi. Qanday? 4 ta texnologiya orqali:
- Prefetching - oldindan yuklash
- Streaming - oqim sifatida yuborish
- Client-side Transitions - client tomonida almashtirish
- Loading UI - yuklanish skeletoni
Navigatsiya qanday ishlaydi - 4 ta kalit tushuncha
Foydalanuvchi link bosadi
│
▼
┌──────────────────┐
│ 1. PREFETCHING │ Link viewport ga kirganda oldindan yuklanadi
└────────┬─────────┘
│
▼
┌──────────────────┐
│ 2. SERVER │ Server Component Payload serverda yaratiladi
│ RENDERING │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ 3. STREAMING │ Server tayyor qismlarni ketma-ket yuboradi
└────────┬─────────┘
│
▼
┌──────────────────────┐
│ 4. CLIENT-SIDE │ Sahifa to'liq yuklanmasdan, faqat o'zgargan
│ TRANSITION │ qism almashtiriladi (SPA kabi)
└──────────────────────┘
1. Prefetching - Oldindan yuklash
Foydalanuvchi hali bosmagan sahifani oldindan fonda yuklash. Natijada link bosilganda sahifa deyarli bir zumda ochiladi.
Next.js <Link> komponenti bilan bog'langan sahifalarni avtomatik prefetch qiladi - link viewport ga kirganda yoki hover qilinganda.
import Link from 'next/link';
export default function Nav() {
return (
<nav>
{/* Link - avtomatik prefetch qiladi */}
<Link href="/blog">Blog</Link>
{/* Oddiy <a> - prefetch QILMAYDI */}
<a href="/contact">Kontakt</a>
</nav>
);
}
Prefetch route turiga qarab farqlanadi:
| Route turi | Prefetch xatti-harakati |
|---|---|
Static route (/about) |
To'liq sahifa oldindan yuklanadi |
Dynamic route (/blog/[slug]) |
loading.tsx bo'lsa - layout + skeleton yuklanadi. Bo'lmasa - prefetch o'tkazib yuboriladi |
Nima uchun dynamic route to'liq prefetch qilinmaydi? Chunki dynamic sahifalarning ma'lumoti so'rov vaqtida aniqlanadi. Masalan, 10,000 ta blog post bor - hammasini oldindan yuklash mantiqiy emas.
2. Streaming - Ma'lumotni oqim sifatida yuborish
Server butun sahifani tayyorlab bo'lishni kutmasdan, tayyor bo'lgan qismlarni ketma-ket yuboradi:
Oddiy rendering:
Server: [=========== to'liq sahifa tayyor ===========] → Client ga yuborish
(uzoq kutish)
Streaming bilan:
Server: [Layout tayyor] → yuborish
[Sidebar tayyor] → yuborish
[Content tayyor] → yuborish
▲ darhol ▲ tezda ▲ oxirgi qism
Streaming ni yoqish - loading.tsx
// app/dashboard/loading.tsx
export default function Loading() {
return (
<div className="animate-pulse">
<div className="h-8 bg-gray-200 rounded w-1/3 mb-4" />
<div className="h-4 bg-gray-200 rounded w-full mb-2" />
<div className="h-4 bg-gray-200 rounded w-2/3 mb-2" />
<div className="h-4 bg-gray-200 rounded w-1/2" />
</div>
);
}
Ichkarida Next.js shunday qiladi:
// Next.js avtomatik ravishda:
<Layout>
<Suspense fallback={<Loading />}>
<Page /> {/* Ma'lumot yuklanguncha Loading ko'rsatiladi */}
</Suspense>
</Layout>
loading.tsx ning afzalliklari:
- Foydalanuvchi darhol vizual javob oladi (skeleton)
- Layout interaktiv bo'lib qoladi (sidebar, nav ishlayveradi)
- Navigatsiyani to'xtatish mumkin (boshqa linkni bosish)
- Core Web Vitals yaxshilanadi (TTFB, FCP, TTI)
3. Client-side Transitions
An'anaviy server-rendered saytlarda har bir navigatsiya to'liq sahifa yuklanishiga olib keladi - state yo'qoladi, scroll qaytadi, barcha narsa qayta yuklanadi.
Next.js <Link> bilan client-side transition qiladi:
An'anaviy sayt: Next.js:
┌──────────────┐ ┌──────────────┐
│ Header │ ← qayta yuklanadi│ Header │ ← O'ZGARMAYDI
│ Sidebar │ ← qayta yuklanadi│ Sidebar │ ← O'ZGARMAYDI
│ ┌──────────┐ │ │ ┌──────────┐ │
│ │ Content │ │ ← qayta yuklanadi│ │ Content │ │ ← FAQAT SHU
│ └──────────┘ │ │ └──────────┘ │ YANGILANADI
│ Footer │ ← qayta yuklanadi│ Footer │ ← O'ZGARMAYDI
└──────────────┘ └──────────────┘
Natijada server-rendered ilova SPA kabi tez ishlaydi.
4. Navigatsiya sekin bo'lishi mumkin bo'lgan holatlar
Muammo 1: Dynamic route da loading.tsx yo'q
❌ Yomon - foydalanuvchi kutib turadi:
app/blog/[slug]/
└── page.tsx # Server javob berguncha bo'sh ekran
✅ Yaxshi - darhol skeleton ko'rsatiladi:
app/blog/[slug]/
├── loading.tsx # Skeleton darhol ko'rsatiladi
└── page.tsx # Ma'lumot tayyor bo'lganda almashadi
Muammo 2: generateStaticParams yo'q
Agar blog postlarni build vaqtida generatsiya qilish mumkin bo'lsa, generateStaticParams qo'shing:
// app/blog/[slug]/page.tsx
// Build vaqtida barcha postlar uchun statik sahifalar yaratiladi
export async function generateStaticParams() {
const posts = await fetch('https://api.example.com/posts')
.then(res => res.json());
return posts.map(post => ({
slug: post.slug,
}));
// Natija: [{ slug: "post-1" }, { slug: "post-2" }, ...]
}
export default async function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const post = await getPost(slug);
return <article>{post.title}</article>;
}
Natija: /blog/post-1, /blog/post-2 sahifalar build vaqtida tayyor bo'ladi - serverga so'rov yuborilmaydi, deyarli bir zumda ochiladi.
Muammo 3: Sekin internet
Prefetch tugamasdan foydalanuvchi link bosishi mumkin. useLinkStatus hook bilan darhol vizual feedback bering:
// app/ui/loading-indicator.tsx
'use client';
import { useLinkStatus } from 'next/link';
export default function LoadingIndicator() {
const { pending } = useLinkStatus();
return (
<span
aria-hidden
className={`loading-dot ${pending ? 'is-pending' : ''}`}
/>
);
}
/* 100ms kechikish bilan - tez navigatsiyada ko'rinmaydi */
.loading-dot {
opacity: 0;
transition: opacity 0.2s;
}
.loading-dot.is-pending {
opacity: 1;
animation: pulse 1s infinite;
animation-delay: 100ms;
}
5. Prefetch ni boshqarish
Prefetch ni o'chirish
Juda ko'p linklar bo'lganda (masalan, cheksiz scroll jadval) resurslarni tejash uchun:
<Link prefetch={false} href="/blog">
Blog
</Link>
Faqat hover da prefetch (optimal yondashuv)
Barcha linklarni emas, faqat foydalanuvchi ustiga sichqoncha olib borganda prefetch qilish:
// app/ui/hover-prefetch-link.tsx
'use client';
import Link from 'next/link';
import { useState } from 'react';
export function HoverPrefetchLink({
href,
children,
}: {
href: string;
children: React.ReactNode;
}) {
const [active, setActive] = useState(false);
return (
<Link
href={href}
prefetch={active ? null : false}
onMouseEnter={() => setActive(true)}
>
{children}
</Link>
);
}
Qachon qaysi strategiya?
| Strategiya | Qachon ishlatish |
|---|---|
| Default (prefetch={undefined}) | Ko'p hollarda - viewport ga kirganda prefetch |
prefetch={false} |
Juda ko'p linklar (infinite scroll, katta jadvallar) |
| Hover prefetch | O'rtacha ko'p linklar - tezlik + resurs tejash balansi |
6. Native History API
Ba'zan URL ni o'zgartirish kerak, lekin sahifani qayta yuklashni xohlamaysiz. Masalan: sort, filter, til almashtirish.
pushState - Tarixga yangi yozuv qo'shish
Foydalanuvchi "Orqaga" tugmasi bilan qaytishi mumkin:
// app/ui/sort-products.tsx
'use client';
import { useSearchParams } from 'next/navigation';
export default function SortProducts() {
const searchParams = useSearchParams();
function updateSorting(sortOrder: string) {
const params = new URLSearchParams(searchParams.toString());
params.set('sort', sortOrder);
window.history.pushState(null, '', `?${params.toString()}`);
// URL: /products?sort=asc
// Sahifa QAYTA YUKLANMAYDI
// "Orqaga" tugmasi bilan oldingi holatga qaytish mumkin
}
return (
<>
<button onClick={() => updateSorting('asc')}>
Arzon → Qimmat
</button>
<button onClick={() => updateSorting('desc')}>
Qimmat → Arzon
</button>
</>
);
}
replaceState - Joriy tarix yozuvini almashtirish
Foydalanuvchi "Orqaga" tugmasi bilan qayta olmaydi:
// app/ui/locale-switcher.tsx
'use client';
import { usePathname } from 'next/navigation';
export function LocaleSwitcher() {
const pathname = usePathname();
function switchLocale(locale: string) {
const newPath = `/${locale}${pathname}`;
window.history.replaceState(null, '', newPath);
// URL: /uz/about → /en/about
// Sahifa QAYTA YUKLANMAYDI
// "Orqaga" tugmasi bilan /uz/about ga qaytib BO'LMAYDI
}
return (
<>
<button onClick={() => switchLocale('uz')}>O'zbekcha</button>
<button onClick={() => switchLocale('en')}>English</button>
<button onClick={() => switchLocale('ru')}>Русский</button>
</>
);
}
Muhim: Bu usullar Next.js Router bilan sinxronlashadi -
usePathnamevauseSearchParamsavtomatik yangilanadi.
pushState vs replaceState
| Metod | "Orqaga" tugmasi | Qachon ishlatish |
|---|---|---|
pushState |
Oldingi holatga qaytadi | Sort, filter, paginatsiya |
replaceState |
Qaytmaydi | Til almashtirish, redirect |
7. Barcha navigatsiya usullari - Qiyoslash
| Usul | Turi | Prefetch | Qachon ishlatish |
|---|---|---|---|
<Link href="/page"> |
Deklarativ | Ha | Asosiy navigatsiya |
useRouter().push() |
Programmatik | Yo'q | Event handler ichida |
useRouter().replace() |
Programmatik | Yo'q | Tarixda iz qoldirmasdan |
useRouter().refresh() |
Programmatik | — | Joriy sahifani yangilash |
history.pushState() |
Native | Yo'q | URL o'zgartirish |
history.replaceState() |
Native | Yo'q | URL almashtirish |
<a href="/page"> |
HTML | Yo'q | ISHLATMANG - to'liq yuklaydi |
8. To'liq navigatsiya jarayoni
Foydalanuvchi /blog sahifasida. /blog/post-1 ga o'tmoqchi:
1. <Link href="/blog/post-1"> viewport ga kiradi
└── Prefetch boshlanadi (fonda)
├── Static → to'liq sahifa yuklanadi
└── Dynamic → loading.tsx + layout yuklanadi
2. Foydalanuvchi linkni bosadi
└── Client-side transition boshlanadi
├── Layout SAQLANADI (qayta render yo'q)
├── loading.tsx skeleton DARHOL ko'rsatiladi
└── Server ma'lumotni stream qiladi
3. Server javob tayyor
└── Skeleton → haqiqiy kontent bilan almashadi
└── Navigatsiya tugadi!
Xulosa - Asosiy qoidalar
-
Har doim
<Link>ishlatang,<a>emas - prefetching va client-side transition uchun -
Dynamic route larga
loading.tsxqo'shing - darhol vizual feedback uchun -
Imkon bo'lsa
generateStaticParamsbilan statik sahifalar yarating - eng tez variant - Ko'p linklar bo'lsa prefetch strategiyasini optimallashtiring
-
URL o'zgartirish uchun
pushState/replaceStateishlatang - sahifa yuklanmaydi
Bu maqola Next.js 15+ rasmiy dokumentatsiyasi asosida yozilgan.
(https://www.matkarim.uz)
Top comments (0)