مفهوم App Router و تفاوت آن با Pages Router
Next.js دو سیستم مسیریابی و ساختاردهی برنامه دارد: Pages Router که قدیمیتر است و App Router که از نسخهی ۱۳ معرفی شد و امروز روش توصیهشده برای پروژههای جدید است. چون هنوز پروژهها و آموزشهای زیادی با Pages Router وجود دارد، لازم است هر دو را بشناسید تا هنگام مراجعه به منابع مختلف دچار سردرگمی نشوید. کل این دوره فقط با App Router پیش میرود.
پیشنیاز
- درس «ساختار فایلها و پوشهها»، بهویژه آشنایی با پوشهی
app - درس «مهمترین تغییرات Next.js 16»
Router یعنی چه؟
Router بخشی از Next.js است که تعیین میکند «با ورود به یک آدرس، کدام فایل اجرا شود». هر دو Router از مسیریابی مبتنی بر فایلسیستم استفاده میکنند، یعنی ساختار پوشهها و فایلها مسیرها را مشخص میکند. تفاوت آنها در پوشهی اصلی، نام فایلهای قراردادی، مدل کامپوننتها و روش دریافت داده است.
Pages Router: مدل قدیمی
در Pages Router پوشهی اصلی pages است و هر فایل داخل آن خودش یک صفحه است:
pages/
├── _app.tsx ← ساختار مشترک همهی صفحات
├── _document.tsx ← تنظیم تگهای html و body
├── index.tsx ← مسیر /
├── about.tsx ← مسیر /about
├── posts/
│ ├── index.tsx ← مسیر /posts
│ └── [slug].tsx ← مسیر /posts/:slug
└── api/
└── posts.ts ← API در مسیر /api/postsویژگیهای اصلی این مدل:
- صفحات برای رندر و تعامل در مرورگر Hydrate میشوند. یعنی کد کامپوننتها به مرورگر فرستاده میشود تا صفحهی HTML آمادهشده را تعاملی کند.
- دریافت داده با توابع ویژهی بیرون از کامپوننت، مثل
getServerSidePropsوgetStaticProps، انجام میشود. - یک Layout مشترک سراسری (
_app.tsx) وجود دارد و Layoutهای تودرتو نیاز به الگوهای دستی دارند. - APIها در پوشهی
pages/apiنوشته میشوند.
App Router: مدل جدید
در App Router پوشهی اصلی app است و هر پوشه یک بخش از آدرس است. فایلهایی با نامهای قراردادی داخل هر پوشه تعیین میکنند آن بخش چه کاری انجام دهد:
app/
├── layout.tsx ← Root Layout
├── page.tsx ← مسیر /
├── about/
│ └── page.tsx ← مسیر /about
├── posts/
│ ├── layout.tsx ← Layout مخصوص بخش posts
│ ├── page.tsx ← مسیر /posts
│ ├── loading.tsx ← وضعیت انتظار
│ └── [slug]/
│ └── page.tsx ← مسیر /posts/:slug
└── api/
└── posts/
└── route.ts ← API در مسیر /api/postsتفاوتهای اصلی App Router:
- Server Components بهصورت پیشفرض: کامپوننتها روی سرور اجرا میشوند و فقط در صورت نیاز با
"use client"به Client Component تبدیل میشوند. این موضوع را در درس «Server Components و کاربرد آنها» کامل میبینیم. - Layoutهای تودرتو: هر پوشه میتواند Layout خودش را داشته باشد و Layoutها بین صفحات مشترک میمانند.
- فایلهای ویژه برای وضعیتها:
loading.tsxبرای انتظار،error.tsxبرای خطا وnot-found.tsxبرای صفحهی پیدا نشد. - دریافت داده داخل کامپوننت: کامپوننت میتواند
asyncباشد و مستقیماًawaitکند. - Streaming و Suspense: بخشهای آمادهی صفحه میتوانند زودتر به کاربر برسند.
- Server Actions و Route Handlers: برای فرمها و APIها با فایلهای
route.ts. - Metadata API: مدیریت عنوان و توضیحات صفحه با خروجیهای ویژهی فایل، بهجای کامپوننت
next/head.
مقایسهی Pages Router و App Router
| موضوع | Pages Router | App Router |
|---|---|---|
| پوشهی اصلی | pages |
app |
| تعریف صفحه | هر فایل یک صفحه است (مثل about.tsx) |
فایل page.tsx داخل پوشه |
| Layout | _app.tsx و _document.tsx |
layout.tsx در هر سطح پوشه |
| مدل کامپوننت | کامپوننتهای کلاینت (با Hydration) | پیشفرض Server Component؛ Client Component با "use client" |
| دریافت داده | getServerSideProps، getStaticProps |
کامپوننت async و await |
| API | pages/api/*.ts |
route.ts (Route Handlers) و Server Actions |
| وضعیت انتظار و خطا | دستی، با State در کامپوننتها (و _error برای خطاها) |
loading.tsx، error.tsx و Suspense |
| Metadata | کامپوننت next/head |
Metadata API |
| Hook مسیریابی | useRouter از next/router |
useRouter از next/navigation |
مثال: فهرست نوشتهها در دو Router
برای دیدن تفاوت در عمل، فهرست نوشتههای DevNotes را یکبار به روش Pages Router و یکبار به روش App Router مینویسیم. نمونهی Pages Router فقط برای شناخت است؛ در پروژهی ما ساخته نمیشود.
Pages Router (فقط برای شناخت)
// pages/posts/index.tsx
import type { GetServerSideProps } from "next";
type Post = { id: number; title: string };
type Props = { posts: Post[] };
export const getServerSideProps: GetServerSideProps<Props> = async () => {
const posts: Post[] = [
{ id: 1, title: "آشنایی با Next.js" },
{ id: 2, title: "مسیریابی در App Router" },
];
return { props: { posts } };
};
export default function PostsPage({ posts }: Props) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}App Router (روش این دوره)
// app/posts/page.tsx
type Post = { id: number; title: string };
async function getPosts(): Promise<Post[]> {
return [
{ id: 1, title: "آشنایی با Next.js" },
{ id: 2, title: "مسیریابی در App Router" },
];
}
export default async function PostsPage() {
const posts = await getPosts();
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}توضیح کد
- در Pages Router داده در تابع جداگانهی
getServerSidePropsگرفته میشود و از طریقpropsبه کامپوننت میرسد. کامپوننت و تابع دریافت داده دو بخش جدا از هماند. - در App Router خود کامپوننت
asyncاست و داده را مستقیماً باawaitمیخواند؛ مسیر داده کوتاهتر و خواناتر است. - خروجی هر دو یک فهرست از عنوان نوشتههاست. تفاوت در محل نوشتن کد، فایل قراردادی و مدل اجرای کامپوننت است.
- نمونهی App Router همان مثال درس «تفاوت React و Next.js» است و در فصل «Rendering و Data Fetching» این الگو را با لایهی دسترسی به داده کاملتر میکنیم.
چگونه تشخیص دهیم کد مربوط به کدام Router است؟
وقتی مثالی در اینترنت میبینید، این نشانهها کمک میکنند:
| نشانه | Router مربوط |
|---|---|
پوشهی pages، فایلهای _app.tsx و _document.tsx |
Pages Router |
getServerSideProps یا getStaticProps یا getStaticPaths |
Pages Router |
import { useRouter } from "next/router" |
Pages Router |
پوشهی app، فایلهای page.tsx و layout.tsx |
App Router |
"use client" یا "use server" در ابتدای فایل |
App Router |
import { useRouter } from "next/navigation" |
App Router |
آیا میتوان هر دو را همزمان داشت؟
بله. یک پروژه میتواند هم پوشهی app و هم پوشهی pages داشته باشد؛ این قابلیت برای مهاجرت تدریجی پروژههای قدیمی طراحی شده است. اما اگر هر دو Router یک مسیر مشابه را تعریف کنند، تداخل پیش میآید و Build خطا میدهد. در پروژهی DevNotes فقط از پوشهی app استفاده میکنیم و پوشهی pages را نمیسازیم.
چرا در این دوره فقط App Router؟
- App Router روش توصیهشده برای پروژههای جدید است و create-next-app آن را بهصورت پیشفرض پیشنهاد میکند.
- قابلیتهای جدید Next.js 16، مثل Cache Components،
use cache، Server Actions و Partial Prerendering، بر پایهی App Router ارائه میشوند. - Pages Router همچنان پشتیبانی میشود و پروژههای موجود با آن کار میکنند. مهاجرت پروژهی قدیمی به App Router خارج از محدودهی این دوره است.
جمعبندی
- Next.js دو Router دارد: Pages Router (پوشهی
pages، مدل قدیمی) و App Router (پوشهیapp، مدل جدید و توصیهشده). - App Router بر پایهی Server Component، Layoutهای تودرتو، فایلهای ویژهی
loading.tsxوerror.tsxو دریافت داده در خود کامپوننت ساخته شده است. - در Pages Router دریافت داده با توابعی مثل
getServerSidePropsانجام میشود و Layoutها از_app.tsxمیآیند. - با نشانههایی مثل
next/routerدر برابرnext/navigationمیتوان کد هر Router را از هم تشخیص داد. - این دوره فقط با App Router و Next.js 16 پیش میرود.
- در درس بعد، «ساخت صفحات با page.tsx»، ساخت صفحه در App Router را عملی تمرین میکنیم.
