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)