انتقال‌های سمت کلاینت در Next.js – بهینه‌سازی ناوبری با prefetch، loading و history API

Next.js با استفاده از انتقال‌های سمت کلاینت، تجربه‌ای روان و سریع برای ناوبری بین صفحات فراهم می‌کند. این مقاله نحوهٔ عملکرد <Link>، دلایل کندی ناوبری، راهکارهایی مانند loading.tsx، prefetch روی hover، و استفاده از history API برای به‌روزرسانی URL بدون بارگذاری مجدد را بررسی می‌کند.

client-side transitionsloading.tsxuseLinkStatuswindow.history

~3 دقیقه مطالعه • بروزرسانی ۳ آبان ۱۴۰۴

مقدمه


در حالت سنتی، ناوبری به صفحات رندر شده در سرور باعث بارگذاری کامل صفحه می‌شود که وضعیت را پاک کرده، موقعیت اسکرول را ریست می‌کند و تعامل‌پذیری را متوقف می‌سازد. Next.js با استفاده از انتقال‌های سمت کلاینت و کامپوننت <Link> این مشکل را حل می‌کند.


مزایای انتقال سمت کلاینت


  • حفظ لایه‌ها و UI مشترک
  • جایگزینی صفحه فعلی با حالت بارگذاری یا صفحه جدید
  • احساس اپلیکیشن کلاینتی در اپلیکیشن‌های سروری

دلایل کندی ناوبری و راهکارها


۱. مسیرهای پویا بدون loading.tsx


در مسیرهای پویا، اگر فایل loading.tsx وجود نداشته باشد، کاربر باید منتظر پاسخ سرور بماند. افزودن این فایل باعث پیش‌بارگذاری جزئی و نمایش UI موقتی می‌شود:


// app/blog/[slug]/loading.tsx
export default function Loading() {
  return <LoadingSkeleton />;
}

۲. نبود generateStaticParams


اگر مسیر پویا قابل پیش‌پردازش باشد ولی تابع generateStaticParams تعریف نشده باشد، مسیر به‌صورت پویا در زمان درخواست رندر می‌شود:


export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
  return posts.map((post) => ({ slug: post.slug }))
}

۳. شبکه‌های کند


در شبکه‌های ضعیف، ممکن است پیش‌بارگذاری قبل از کلیک کامل نشود. برای بازخورد فوری، از هوک useLinkStatus استفاده کنید:


// app/ui/loading-indicator.tsx
'use client'
import { useLinkStatus } from 'next/link'

export default function LoadingIndicator() {
  const { pending } = useLinkStatus()
  return (
    <span aria-hidden className={`link-hint ${pending ? 'is-pending' : ''}`} />
  )
}

۴. غیرفعال‌سازی prefetch


برای کاهش مصرف منابع، می‌توان prefetch را غیرفعال کرد یا فقط هنگام hover فعال ساخت:


// app/ui/hover-prefetch-link.tsx
'use client'
import Link from 'next/link'
import { useState } from 'react'

function HoverPrefetchLink({ href, children }) {
  const [active, setActive] = useState(false)
  return (
    <Link
      href={href}
      prefetch={active ? null : false}
      onMouseEnter={() => setActive(true)}
    >
      {children}
    </Link>
  )
}

۵. تأخیر در hydration


کامپوننت <Link> باید ابتدا hydrate شود تا بتواند پیش‌بارگذاری کند. برای بهبود:


  • استفاده از @next/bundle-analyzer برای کاهش حجم باندل
  • انتقال منطق از کلاینت به سرور

استفاده از History API


Next.js اجازه استفاده از window.history.pushState و replaceState را برای به‌روزرسانی URL بدون بارگذاری مجدد می‌دهد:


مثال: مرتب‌سازی لیست محصولات


'use client'
import { useSearchParams } from 'next/navigation'

export default function SortProducts() {
  const searchParams = useSearchParams()
  function updateSorting(sortOrder) {
    const params = new URLSearchParams(searchParams.toString())
    params.set('sort', sortOrder)
    window.history.pushState(null, '', `?${params.toString()}`)
  }
}

مثال: تغییر زبان اپلیکیشن


'use client'
import { usePathname } from 'next/navigation'

export function LocaleSwitcher() {
  const pathname = usePathname()
  function switchLocale(locale) {
    const newPath = `/${locale}${pathname}`
    window.history.replaceState(null, '', newPath)
  }
}

جمع‌بندی


انتقال‌های سمت کلاینت در Next.js باعث ناوبری سریع، حفظ وضعیت و تجربه کاربری روان می‌شوند. با استفاده از loading.tsx، useLinkStatus، و History API می‌توان مسیرهای پویا را بهینه کرد و بازخورد فوری به کاربر ارائه داد.


نوشته و پژوهش شده توسط دکتر شاهین صیامی