Next.js
مسیریاب app
برنامه تان را بسیازید
مسیریابی Routing
لینک دادن و پیمایش

لینک دهی و پیمایش

در Next.js، چهار روش برای پیمایش بین مسیرها وجود دارد:

این صفحه به شما نحوه‌ی استفاده از هر یک از این گزینه‌ها را آموزش می‌دهد و همچنین به نحوه‌ی کارکرد پیمایش در Next.js می‌پردازد.

کامپوننت <Link>

<Link> یک کامپوننت داخلی است که برچسب تگ <a> در HTML را برای فراهم کردن پیش-بارگذاری (prefetching) و پیمایش سمت کاربر (client-side navigation) بین مسیرها توسعه می‌دهد. این روش اصلی و توصیه شده برای پیمایش بین مسیرها در Next.js است.

می‌توانید با وارد کردن آن از next/link و پاس دادن یک پراپ به نام href به کامپوننت، از آن استفاده کنید:

app/page.tsx
import Link from 'next/link'
 
export default function Page() {
	return <Link href="/dashboard">Dashboard</Link>
}

شما می‌توانید پراپ های (props) اختیاری دیگری را به <Link> پاس بدهید. برای اطلاعات بیشتر به بخش مرجع API مراجعه کنید.

مثال ها

لینک دهی به بخش‌های داینامیک

هنگام لینک کردن به بخش های داینامیک dynamic segments، می توانید از template literals and interpolation (opens in a new tab) برای ایجاد لیستی از لینک ها استفاده کنید. به عنوان مثال، برای ایجاد لیستی از پست های وبلاگ:

app/blog/PostList.js
import Link from 'next/link'
 
export default function PostList({ posts }) {
	return (
		<ul>
			{posts.map((post) => (
				<li key={post.id}>
					<Link href={`/blog/${post.slug}`}>{post.title}</Link>
				</li>
			))}
		</ul>
	)
}

بررسی لینک‌های فعال

می توانید از usePathname() برای تشخیص فعال بودن یک لینک استفاده کنید. به عنوان مثال، برای اضافه کردن یک کلاس به لینک فعال، می توانید بررسی کنید که آیا مسیر فعلی pathname با آدرس href لینک مطابقت دارد:

@/app/ui/nav-links.tsx
'use client'
 
import { usePathname } from 'next/navigation'
import Link from 'next/link'
 
export function Links() {
	const pathname = usePathname()
 
	return (
		<nav>
			<Link
				className={`link ${pathname === '/' ? 'active' : ''}`}
				href="/"
			>
				Home
			</Link>
 
			<Link
				className={`link ${pathname === '/about' ? 'active' : ''}`}
				href="/about"
			>
				About
			</Link>
		</nav>
	)
}

اسکرول به یک شناسه خاص id

رفتار پیش فرض مسیریاب برنامه Next.js این است که هنگام مسیریابی جدید به بالای صفحه اسکرول کند یا موقعیت اسکرول را برای پیمایش به جلو و عقب حفظ کند.

اگر می‌خواهید هنگام پیمایش به یک شناسه id خاص اسکرول کنید، می‌توانید URL خود را با یک لینک هش # اضافه کنید یا فقط یک لینک هش را به پراپ href پاس دهید. این امکان‌پذیر است زیرا <Link> به یک المنت <a> رندر می‌شود.

<Link href="/dashboard#settings">Settings</Link>
 
// Output
<a href="/dashboard#settings">Settings</a>

خوب است بدانید:

  • در صورت پیمایش، Next.js به صفحه Page اسکرول می‌کند اگر در هنگام پیمایش قابل مشاهده نباشد.

غیرفعال کردن بازیابی اسکرول

رفتار پیش فرض مسیریاب برنامه Next.js این است که هنگام مسیریابی جدید به بالای صفحه اسکرول کند یا موقعیت اسکرول را برای پیمایش به جلو و عقب حفظ کند. اگر می‌خواهید این رفتار را غیرفعال کنید، می‌توانید پاس بدهید scroll={false} را به کامپوننت <Link>, یا scroll: false را به router.push() یا router.replace().

// next/link
<Link href="/dashboard" scroll={false}>
	Dashboard
</Link>
// useRouter
import { useRouter } from 'next/navigation'
 
const router = useRouter()
 
router.push('/dashboard', { scroll: false })

هوک useRouter()

هوک useRouter به شما امکان می دهد مسیرها را به صورت برنامه ریزی شده از کامپوننت های سمت کاربر Client Components تغییر دهید.

app/page.js
'use client'
 
import { useRouter } from 'next/navigation'
 
export default function Page() {
	const router = useRouter()
 
	return (
		<button type="button" onClick={() => router.push('/dashboard')}>
			Dashboard
		</button>
	)
}

برای لیست کامل متدهای useRouter، به بخش مرجع API مراجعه کنید.

توصیه : از کامپوننت <Link> برای پیمایش بین مسیرها استفاده کنید، مگر اینکه نیاز خاصی به استفاده از useRouter داشته باشید.

تابع redirect

برای کامپوننت های سرور، به جای آن از تابع redirect استفاده کنید.

app/team/[id]/page.tsx
import { redirect } from 'next/navigation'
 
async function fetchTeam(id: string) {
	const res = await fetch('https://...')
	if (!res.ok) return undefined
	return res.json()
}
 
export default async function Profile({ params }: { params: { id: string } }) {
	const team = await fetchTeam(params.id)
	if (!team) {
		redirect('/login')
	}
 
	// ...
}

خوب است بدانید:

  • تابع redirect به طور پیش فرض کد وضعیت 307 (ریدایرکت موقت) را برمیگرداند. هنگامی که در یک اکشن سرور (Server Action) استفاده می شود، کد وضعیت 303 (مشاهده دیگر) را برمیگرداند که به طور رایج برای ریدایرکت به صفحه موفقیت پس از درخواست POST استفاده می شود.
  • تابع redirect به صورت داخلی خطا پرتاب می کند، بنابراین باید خارج از بلوک های try/catch فراخوانی شود.
  • تابع redirect را می توان در کامپوننت های سمت کلاینت در طول فرآیند رندر فراخوانی کرد، اما در هندلرهای رویداد (event handlers) قابل استفاده نیست. در عوض می توانید از هوک useRouter استفاده کنید.
  • تابع redirect همچنین URL های مطلق (absolute URLs) را می پذیرد و می توان از آن برای ریدایرکت به لینک های خارجی استفاده کرد.
  • اگر می خواهید قبل از فرآیند رندر، هدایت انجام دهید، از next.config.js یا Middleware استفاده کنید.

برای اطلاعات بیشتر به بخش مرجع API تابع redirect مراجعه کنید.

استفاده از History API بومی

Next.js به شما امکان می‌دهد از متدهای بومی window.history.pushState (opens in a new tab) و window.history.replaceState (opens in a new tab) برای به‌روزرسانی تاریخچه مرورگر بدون بارگذاری مجدد صفحه استفاده کنید.

تکرارهای pushState و replaceState با روتر Next.js ادغام می‌شوند و به شما امکان همگام‌سازی با usePathname و useSearchParams را می‌دهند.

window.history.pushState

از این تابع برای افزودن یک ورودی جدید به تاریخچه مرورگر استفاده کنید. کاربر می‌تواند به حالت قبلی بازگردد. به عنوان مثال، برای مرتب‌سازی لیست محصولات:

'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()}`)
	}
 
	return (
		<>
			<button onClick={() => updateSorting('asc')}>Sort Ascending</button>
			<button onClick={() => updateSorting('desc')}>
				Sort Descending
			</button>
		</>
	)
}

window.history.replaceState

از این تابع برای جایگزینی ورودی فعلی در تاریخچه مرورگر استفاده کنید. کاربر قادر به بازگشت به حالت قبلی نیست. به عنوان مثال، برای تغییر زبان برنامه:

'use client'
 
import { usePathname } from 'next/navigation'
 
export function LocaleSwitcher() {
	const pathname = usePathname()
 
	function switchLocale(locale: string) {
		// e.g. '/en/about' or '/fr/contact'
		const newPath = `/${locale}${pathname}`
		window.history.replaceState(null, '', newPath)
	}
 
	return (
		<>
			<button onClick={() => switchLocale('en')}>English</button>
			<button onClick={() => switchLocale('fr')}>French</button>
		</>
	)
}

نحوه عملکرد مسیریابی و پیمایش

روتر برنامه از یک رویکرد ترکیبی برای مسیریابی و پیمایش استفاده می کند. در سمت سرور، کد برنامه شما به طور خودکار بر اساس بخش های مسیر، تقسیم بندی code-split می شود. در سمت کاربر، Next.js بخش های مسیر را پیش-بارگذاری prefetches و کش caches می کند. این بدان معنی است که زمانی که کاربر به یک مسیر جدید هدایت می شود، مرورگر صفحه را دوباره بارگذاری نمی کند و تنها بخش هایی از مسیر که تغییر کرده اند، دوباره رندر می شوند - این امر باعث بهبود تجربه پیمایش و عملکرد می شود.

1. تقسیم بندی کد (Code Splitting)

تقسیم بندی کد به شما امکان می دهد کد برنامه خود را به بسته های کوچکتر تقسیم کنید تا توسط مرورگر دانلود و اجرا شوند. این کار باعث کاهش حجم داده های منتقل شده و زمان اجرای هر درخواست می شود که در نهایت منجر به بهبود عملکرد می شود.

کامپوننت های سمت سرور Server Components به شما اجازه می دهند تا کد برنامه تان به طور خودکار بر اساس بخش های مسیر تقسیم بندی شود. این بدین معناست که در هنگام پیمایش، تنها کد مورد نیاز برای مسیر فعلی بارگذاری می شود.

2. پیش بارگذاری (Prefetching)

پیش بارگذاری روشی است برای بارگذاری اولیه یک مسیر در پس زمینه قبل از اینکه کاربر از آن بازدید کند.

در Next.js مسیرها به دو روش پیش بارگذاری می شوند:

  • کامپوننت <Link>: مسیرها به طور خودکار با مشاهده شدن در ناحیه دید کاربر، پیش بارگذاری می شوند. پیش بارگذاری زمانی اتفاق می افتد که صفحه برای اولین بار بارگذاری شود یا زمانی که از طریق اسکرول کردن به دید کاربر برسد.
  • router.prefetch() : از هوک useRouter می توان برای پیش بارگذاری مسیرها به صورت برنامه ریزی شده استفاده کرد.

رفتار پیش فرض پیش بارگذاری <Link> (یعنی زمانی که prefetch مشخص نشده یا روی null تنظیم شده باشد) بسته به نحوه استفاده شما از loading.js متفاوت است. تنها طرح بندی به اشتراک گذاشته شده، پایین درخت tree کامپوننت ها تا اولین فایل loading.js پیش بارگذاری می شود و به مدت 30 ثانیه کش می شود. این کار هزینه بارگذاری کل یک مسیر داینامیک را کاهش می دهد و به این معنی است که می توانید یک حالت بارگذاری فوری instant loading state را برای بازخورد بصری بهتر به کاربران نشان دهید.

با تنظیم prefetch روی false می توانید پیش بارگذاری را غیرفعال کنید. همچنین، با تنظیم prefetch روی true می توانید داده های کامل صفحه را فراتر از مرزهای بارگذاری پیش بارگذاری کنید.

برای اطلاعات بیشتر به بخش مرجع API <Link> مراجعه کنید.

خوب است بدانید :

  • یش بارگذاری در محیط توسعه development فعال نیست، بلکه فقط در محیط تولید production فعال است.

3. کش کردن

Next.js یک کش سمت کاربر درون حافظه به نام کش روتر Router Cache دارد. با پیمایش کاربران در اطراف برنامه، بار خروجی کامپوننت های سمت سرور React برای بخش های مسیر پیش بارگذاری prefetched شده و مسیرهای بازدید شده در کش ذخیره می شوند.

این بدان معنی است که در هنگام پیمایش، تا حد امکان از کش استفاده مجدد می شود، به جای اینکه درخواست جدیدی به سرور ارسال شود - عملکرد با کاهش تعداد درخواست ها و داده های منتقل شده بهبود می یابد.

درباره نحوه عملکرد Router Cache و نحوه پیکربندی آن بیشتر بیاموزید.

4. رندر جزئی (Partial Rendering)

رندر جزئی به این معنی است که فقط بخش های مسیر که در هنگام پیمایش تغییر می کنند، در سمت کاربر دوباره رندر می شوند و هر بخش مشترکی حفظ می شود.

به عنوان مثال، هنگام پیمایش بین دو مسیر هم سطح، /dashboard/settings و /dashboard/analytics، صفحات settings و analytics رندر می شوند و طرح بندی مشترک dashboard حفظ می شود.


نحوه عملکرد رندر جزئینحوه عملکرد رندر جزئی

بدون رندر جزئی، هر پیمایشی باعث می شود کل صفحه در سمت کاربر دوباره رندر شود. رندر کردن فقط بخشی که تغییر می کند، مقدار داده های منتقل شده و زمان اجرا را کاهش می دهد و در نتیجه عملکرد را بهبود می بخشد.

5. پیمایش نرم (Soft Navigation)

مرورگرها هنگام پیمایش بین صفحات، یک "پیمایش سخت" (hard navigation) انجام می دهند. روتر برنامه Next.js امکان "پیمایش نرم" بین صفحات را فراهم می کند و اطمینان می دهد که فقط بخش های مسیری که تغییر کرده اند، دوباره رندر می شوند (رندر جزئی). این کار باعث حفظ وضعیت React در سمت کاربر در هنگام پیمایش می شود.

6. پیمایش به جلو و عقب (Back and Forward Navigation)

به طور پیش فرض، Next.js موقعیت اسکرول را برای پیمایش به جلو و عقب حفظ می کند و بخش های مسیر را در "کش روتر" Router Cache دوباره استفاده می کند.

7. مسیریابی بین پوشه های pages/ و app/

هنگام مهاجرت تدریجی از pages/ به app/، روتر Next.js به طور خودکار پیمایش سخت بین این دو را مدیریت می کند. برای تشخیص انتقال از pages/ به app/، یک فیلتر روتر سمت کاربر وجود دارد که از بررسی احتمالی مسیرهای برنامه استفاده می کند، که گاهی اوقات می تواند منجر به نتایج مثبت کاذب شود. به طور پیش فرض، چنین رویدادهایی باید بسیار نادر باشند، زیرا احتمال مثبت کاذب را روی 0.01% تنظیم می کنیم. این احتمال را می توان از طریق گزینه experimental.clientRouterFilterAllowedRate در next.config.js سفارشی کرد. مهم است که توجه داشته باشید که کاهش نرخ مثبت کاذب، اندازه فیلتر ایجاد شده در بسته سمت کاربر را افزایش می دهد.

از طرف دیگر، اگر تمایل دارید این مدیریت را به طور کامل غیرفعال کنید و مسیریابی بین pages/ و app/ را به صورت دستی مدیریت کنید، می توانید experimental.clientRouterFilter را روی false در next.config.js تنظیم کنید. وقتی این ویژگی غیرفعال باشد، هر مسیر داینامیکی در pages/ که با مسیرهای app/ همپوشانی داشته باشد، به طور پیش فرض به درستی پیمایش نخواهد کرد.