DEV Community

MATKARIM MATKARIMOV
MATKARIM MATKARIMOV

Posted on

Next.js - Linking va Navigatsiya To'liq Qo'llanma


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:

  1. Prefetching - oldindan yuklash
  2. Streaming - oqim sifatida yuborish
  3. Client-side Transitions - client tomonida almashtirish
  4. 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)
└──────────────────────┘
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

Ichkarida Next.js shunday qiladi:

// Next.js avtomatik ravishda:
<Layout>
  <Suspense fallback={<Loading />}>
    <Page />   {/* Ma'lumot yuklanguncha Loading ko'rsatiladi */}
  </Suspense>
</Layout>
Enter fullscreen mode Exit fullscreen mode

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
└──────────────┘                  └──────────────┘
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>;
}
Enter fullscreen mode Exit fullscreen mode

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' : ''}`}
    />
  );
}
Enter fullscreen mode Exit fullscreen mode
/* 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;
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Muhim: Bu usullar Next.js Router bilan sinxronlashadi - usePathname va useSearchParams avtomatik 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!
Enter fullscreen mode Exit fullscreen mode

Xulosa - Asosiy qoidalar

  1. Har doim <Link> ishlatang, <a> emas - prefetching va client-side transition uchun
  2. Dynamic route larga loading.tsx qo'shing - darhol vizual feedback uchun
  3. Imkon bo'lsa generateStaticParams bilan statik sahifalar yarating - eng tez variant
  4. Ko'p linklar bo'lsa prefetch strategiyasini optimallashtiring
  5. URL o'zgartirish uchun pushState/replaceState ishlatang - sahifa yuklanmaydi

Bu maqola Next.js 15+ rasmiy dokumentatsiyasi asosida yozilgan.
(https://www.matkarim.uz)

Top comments (0)