فارسی

رابط‌های کاربری مقیاس‌پذیر و پویا در Next.js را فعال کنید. راهنمای جامع ما گروه‌های مسیر (Route Groups) برای سازماندهی و مسیرهای موازی (Parallel Routes) برای داشبوردهای پیچیده را پوشش می‌دهد. همین حالا سطح خود را بالا ببرید!

تسلط بر App Router در Next.js: نگاهی عمیق به معماری گروه‌های مسیر و مسیرهای موازی

انتشار App Router در Next.js یک تغییر پارادایم در نحوه ساخت اپلیکیشن‌های وب توسط توسعه‌دهندگان با این فریمورک محبوب React بود. App Router با فاصله گرفتن از قراردادهای مبتنی بر فایل در Pages Router، یک مدل قدرتمندتر، انعطاف‌پذیرتر و سرور-محور را معرفی کرد. این تحول به ما این امکان را می‌دهد که رابط‌های کاربری بسیار پیچیده و با کارایی بالا را با کنترل و سازماندهی بیشتری ایجاد کنیم. از جمله تحول‌آفرین‌ترین ویژگی‌های معرفی شده می‌توان به گروه‌های مسیر (Route Groups) و مسیرهای موازی (Parallel Routes) اشاره کرد.

برای توسعه‌دهندگانی که قصد ساخت اپلیکیشن‌های در سطح سازمانی (enterprise-grade) را دارند، تسلط بر این دو مفهوم فقط مفید نیست—بلکه ضروری است. آن‌ها چالش‌های رایج معماری مربوط به مدیریت لایوت، سازماندهی مسیرها و ایجاد رابط‌های پویا و چند پنلی مانند داشبوردها را حل می‌کنند. این راهنما یک کاوش جامع در مورد گروه‌های مسیر و مسیرهای موازی، از مفاهیم بنیادی گرفته تا استراتژی‌های پیاده‌سازی پیشرفته و بهترین شیوه‌ها برای مخاطبان جهانی توسعه‌دهنده ارائه می‌دهد.

درک App Router در Next.js: یک یادآوری سریع

قبل از اینکه به جزئیات بپردازیم، بیایید به طور خلاصه اصول اصلی App Router را مرور کنیم. معماری آن بر اساس یک سیستم مبتنی بر دایرکتوری ساخته شده است که در آن پوشه‌ها بخش‌های URL را تعریف می‌کنند. فایل‌های ویژه در این پوشه‌ها، رابط کاربری و رفتار آن بخش را تعریف می‌کنند:

این ساختار، همراه با استفاده پیش‌فرض از کامپوننت‌های سرور React (RSCs)، یک رویکرد سرور-محور را تشویق می‌کند که می‌تواند به طور قابل توجهی عملکرد و الگوهای واکشی داده را بهبود بخشد. گروه‌های مسیر و مسیرهای موازی قراردادهای پیشرفته‌ای هستند که بر این پایه ساخته شده‌اند.

رمزگشایی از گروه‌های مسیر: سازماندهی پروژه برای سلامت روان و مقیاس‌پذیری

با رشد یک اپلیکیشن، تعداد مسیرها می‌تواند غیرقابل کنترل شود. ممکن است مجموعه‌ای از صفحات برای بازاریابی، مجموعه‌ای دیگر برای احراز هویت کاربر و مجموعه‌ای سوم برای داشبورد اصلی اپلیکیشن داشته باشید. از نظر منطقی، این‌ها بخش‌های جداگانه‌ای هستند، اما چگونه آن‌ها را در سیستم فایل خود سازماندهی می‌کنید بدون اینکه URLهای خود را شلوغ کنید؟ این دقیقاً مشکلی است که گروه‌های مسیر حل می‌کنند.

گروه‌های مسیر چه هستند؟

یک گروه مسیر مکانیزمی برای سازماندهی فایل‌ها و بخش‌های مسیر شما به گروه‌های منطقی است بدون اینکه بر ساختار URL تأثیر بگذارد. شما یک گروه مسیر را با قرار دادن نام یک پوشه در داخل پرانتز ایجاد می‌کنید، به عنوان مثال، (marketing) یا (app).

نام پوشه داخل پرانتز صرفاً برای اهداف سازمانی است. Next.js هنگام تعیین مسیر URL آن را کاملاً نادیده می‌گیرد. به عنوان مثال، فایل موجود در app/(marketing)/about/page.js در URL /about ارائه می‌شود، نه /(marketing)/about.

موارد استفاده کلیدی و مزایای گروه‌های مسیر

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

۱. ایجاد لایوت‌های مختلف برای بخش‌های مسیر

این رایج‌ترین و قدرتمندترین مورد استفاده است. یک اپلیکیشن وب با دو بخش اصلی را تصور کنید:

بدون گروه‌های مسیر، اعمال لایوت‌های ریشه متفاوت به این بخش‌ها پیچیده خواهد بود. با گروه‌های مسیر، این کار به طرز باورنکردنی‌ای شهودی است. شما می‌توانید یک فایل layout.js منحصر به فرد در داخل هر گروه ایجاد کنید.

در اینجا یک ساختار فایل معمولی برای این سناریو آمده است:

app/
├── (marketing)/
│   ├── layout.js      // لایوت عمومی با هدر/فوتر بازاریابی
│   ├── page.js        // در '/' رندر می‌شود
│   └── about/
│       └── page.js    // در '/about' رندر می‌شود
├── (app)/
│   ├── layout.js      // لایوت داشبورد با نوار کناری
│   ├── dashboard/
│   │   └── page.js    // در '/dashboard' رندر می‌شود
│   └── settings/
│       └── page.js    // در '/settings' رندر می‌شود
└── layout.js          // لایوت ریشه (مثلاً برای تگ‌های <html> و <body>)

در این معماری:

۲. خارج کردن یک بخش از یک لایوت مشترک

گاهی اوقات، یک صفحه یا بخش خاص نیاز دارد تا به طور کامل از لایوت والد خود جدا شود. یک مثال رایج، فرآیند پرداخت یا یک صفحه فرود ویژه است که نباید ناوبری اصلی سایت را داشته باشد. شما می‌توانید این کار را با قرار دادن مسیر در یک گروهی که از لایوت سطح بالاتر استفاده نمی‌کند، انجام دهید. اگرچه این پیچیده به نظر می‌رسد، اما به سادگی به معنای دادن یک layout.js سطح بالای خودش به یک گروه مسیر است که `children` را از لایوت ریشه رندر نمی‌کند.

مثال عملی: ساخت یک اپلیکیشن چند-لایوتی

بیایید یک نسخه حداقلی از ساختار بازاریابی/اپلیکیشن که در بالا توضیح داده شد را بسازیم.

۱. لایوت ریشه (app/layout.js)

این لایوت حداقل است و برای هر صفحه‌ای اعمال می‌شود. این لایوت ساختار ضروری HTML را تعریف می‌کند.

// app/layout.js
export default function RootLayout({ children }) {
  return (
    <html lang="fa">
      <body>{children}</body>
    </html>
  );
}

۲. لایوت بازاریابی (app/(marketing)/layout.js)

این لایوت شامل یک هدر و فوتر عمومی است.

// app/(marketing)/layout.js
export default function MarketingLayout({ children }) {
  return (
    <div>
      <header>هدر بازاریابی</header>
      <main>{children}</main>
      <footer>فوتر بازاریابی</footer>
    </div>
  );
}

۳. لایوت داشبورد اپلیکیشن (app/(app)/layout.js)

این لایوت ساختار متفاوتی دارد و دارای یک نوار کناری برای کاربران احراز هویت شده است.

// app/(app)/layout.js
export default function AppLayout({ children }) {
  return (
    <div style={{ display: 'flex' }}>
      <aside style={{ width: '200px', borderRight: '1px solid #ccc' }}>
        نوار کناری داشبورد
      </aside>
      <main style={{ flex: 1, padding: '20px' }}>{children}</main>
    </div>
  );
}

با این ساختار، پیمایش به /about صفحه را با `MarketingLayout` رندر می‌کند، در حالی که پیمایش به /dashboard آن را با `AppLayout` رندر می‌کند. URL تمیز و معنایی باقی می‌ماند، در حالی که ساختار فایل پروژه ما کاملاً سازماندهی شده و مقیاس‌پذیر است.

باز کردن قفل رابط‌های کاربری پویا با مسیرهای موازی

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

مسیرهای موازی چه هستند؟

مسیرهای موازی به شما امکان می‌دهند تا یک یا چند صفحه را به طور همزمان در همان لایوت رندر کنید. این مسیرها با استفاده از یک قرارداد پوشه‌بندی ویژه به نام اسلات‌ها (slots) تعریف می‌شوند. اسلات‌ها با استفاده از سینتکس @folderName ایجاد می‌شوند. آن‌ها بخشی از ساختار URL نیستند؛ در عوض، به طور خودکار به عنوان props به نزدیک‌ترین فایل `layout.js` والد مشترک ارسال می‌شوند.

به عنوان مثال، اگر لایوتی دارید که باید یک فید فعالیت تیم و یک نمودار تحلیلی را کنار هم نمایش دهد، می‌توانید دو اسلات تعریف کنید: `@team` و `@analytics`.

ایده اصلی: اسلات‌ها

اسلات‌ها را به عنوان جایگاه‌های نام‌گذاری شده در لایوت خود در نظر بگیرید. فایل لایوت به صراحت این اسلات‌ها را به عنوان props می‌پذیرد و تصمیم می‌گیرد که آن‌ها را کجا رندر کند.

این کامپوننت لایوت را در نظر بگیرید:

// لایوتی که دو اسلات را می‌پذیرد: 'team' و 'analytics'
export default function DashboardLayout({ children, team, analytics }) {
  return (
    <div>
      {children}
      <div style={{ display: 'flex' }}>
        {team}
        {analytics}
      </div>
    </div>
  );
}

در اینجا، `children`، `team` و `analytics` همگی اسلات هستند. `children` یک اسلات ضمنی است که با فایل استاندارد `page.js` در دایرکتوری مطابقت دارد. `team` و `analytics` اسلات‌های صریح هستند که باید با پیشوند `@` در سیستم فایل ایجاد شوند.

ویژگی‌ها و مزایای کلیدی

یک سناریوی واقعی: ساخت یک داشبورد پیچیده

بیایید یک داشبورد در URL /dashboard طراحی کنیم. این داشبورد یک بخش محتوای اصلی، یک پنل فعالیت تیم و یک پنل تحلیل عملکرد خواهد داشت.

ساختار فایل:

app/
└── dashboard/
    ├── @analytics/
    │   ├── page.js          // UI برای اسلات analytics
    │   └── loading.js     // UI بارگذاری مخصوص analytics
    ├── @team/
    │   └── page.js          // UI برای اسلات team
    ├── layout.js            // لایوتی که اسلات‌ها را هماهنگ می‌کند
    └── page.js              // اسلات ضمنی 'children' (محتوای اصلی)

۱. لایوت داشبورد (app/dashboard/layout.js)

این لایوت سه اسلات را دریافت و مرتب می‌کند.

// app/dashboard/layout.js
export default function DashboardLayout({ children, analytics, team }) {
  const isLoggedIn = true; // با منطق احراز هویت واقعی جایگزین شود

  return isLoggedIn ? (
    <div>
      <h1>داشبورد اصلی</h1>
      {children}
      <div style={{ marginTop: '20px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px' }}>
        <div style={{ border: '1px solid blue', padding: '10px' }}>
          <h2>فعالیت تیم</h2>
          {team}
        </div>
        <div style={{ border: '1px solid green', padding: '10px' }}>
          <h2>تحلیل عملکرد</h2>
          {analytics}
        </div>
      </div>
    </div>
  ) : (
    <div>لطفاً برای مشاهده داشبورد وارد شوید.</div>
  );
}

۲. صفحات اسلات (مثلاً app/dashboard/@analytics/page.js)

فایل `page.js` هر اسلات حاوی UI برای آن پنل خاص است.

// app/dashboard/@analytics/page.js
async function getAnalyticsData() {
  // شبیه‌سازی یک درخواست شبکه
  await new Promise(resolve => setTimeout(resolve, 3000));
  return { views: '1.2M', revenue: '$50,000' };
}

export default async function AnalyticsPage() {
  const data = await getAnalyticsData();
  return (
    <div>
      <p>تعداد بازدیدها: {data.views}</p>
      <p>درآمد: {data.revenue}</p>
    </div>
  );
}

// app/dashboard/@analytics/loading.js
export default function Loading() {
  return <p>در حال بارگذاری داده‌های تحلیلی...</p>;
}

با این تنظیمات، هنگامی که کاربر به /dashboard پیمایش می‌کند، Next.js `DashboardLayout` را رندر می‌کند. لایوت محتوای رندر شده از dashboard/page.js، dashboard/@team/page.js و dashboard/@analytics/page.js را به عنوان props دریافت کرده و آن‌ها را بر اساس آن قرار می‌دهد. نکته مهم این است که پنل تحلیلی حالت loading.js خود را به مدت ۳ ثانیه بدون مسدود کردن رندر بقیه داشبورد نشان می‌دهد.

مدیریت مسیرهای نامطابق با `default.js`

یک سوال حیاتی پیش می‌آید: چه اتفاقی می‌افتد اگر Next.js نتواند حالت فعال یک اسلات را برای URL فعلی بازیابی کند؟ به عنوان مثال، در هنگام بارگذاری اولیه یا بارگذاری مجدد صفحه، URL ممکن است /dashboard باشد، که دستورالعمل خاصی برای نمایش محتوا در اسلات‌های @team یا @analytics ارائه نمی‌دهد. به طور پیش‌فرض، Next.js یک خطای 404 را رندر می‌کند.

برای جلوگیری از این امر، می‌توانیم با ایجاد یک فایل default.js در داخل مسیر موازی، یک UI جایگزین (fallback) ارائه دهیم.

مثال:

// app/dashboard/@analytics/default.js
export default function DefaultAnalyticsPage() {
  return (
    <div>
      <p>هیچ داده تحلیلی انتخاب نشده است.</p>
    </div>
  );
}

اکنون، اگر اسلات تحلیلی نامطابق باشد، Next.js به جای یک صفحه 404، محتوای `default.js` را رندر می‌کند. این برای ایجاد یک تجربه کاربری روان، به خصوص در بارگذاری اولیه یک تنظیمات پیچیده مسیر موازی، ضروری است.

ترکیب گروه‌های مسیر و مسیرهای موازی برای معماری‌های پیشرفته

قدرت واقعی App Router زمانی مشخص می‌شود که شما ویژگی‌های آن را با هم ترکیب کنید. گروه‌های مسیر و مسیرهای موازی به زیبایی با هم کار می‌کنند تا معماری‌های اپلیکیشن پیچیده و بسیار سازمان‌یافته‌ای ایجاد کنند.

مورد استفاده: یک نمایشگر محتوای چند-حالتی

پلتفرمی مانند یک گالری رسانه یا یک نمایشگر سند را تصور کنید که در آن کاربر می‌تواند یک آیتم را مشاهده کند اما همچنین یک پنجره مودال را برای دیدن جزئیات آن باز کند بدون اینکه زمینه صفحه پس‌زمینه را از دست بدهد. این اغلب «مسیر رهگیری شده» (Intercepting Route) نامیده می‌شود و یک الگوی قدرتمند است که بر روی مسیرهای موازی ساخته شده است.

بیایید یک گالری عکس ایجاد کنیم. وقتی روی یک عکس کلیک می‌کنید، در یک مودال باز می‌شود. اما اگر صفحه را رفرش کنید یا مستقیماً به URL عکس بروید، باید یک صفحه اختصاصی برای آن عکس نشان داده شود.

ساختار فایل:

app/
├── @modal/(..)(..)photos/[id]/page.js  // مسیر رهگیری شده برای مودال
├── photos/
│   └── [id]/
│       └── page.js                  // صفحه اختصاصی عکس
├── layout.js                        // لایوت ریشه که اسلات @modal را دریافت می‌کند
└── page.js                          // صفحه اصلی گالری

توضیح:

این الگو مسیرهای موازی (اسلات @modal) را با قراردادهای مسیریابی پیشرفته ترکیب می‌کند تا یک تجربه کاربری یکپارچه ایجاد کند که پیاده‌سازی دستی آن بسیار پیچیده خواهد بود.

بهترین شیوه‌ها و دام‌های رایج

بهترین شیوه‌ها برای گروه‌های مسیر

بهترین شیوه‌ها برای مسیرهای موازی

دام‌های رایج برای اجتناب

نتیجه‌گیری: ساختن آینده اپلیکیشن‌های وب

App Router در Next.js، با ویژگی‌هایی مانند گروه‌های مسیر و مسیرهای موازی، یک پایه محکم و مقیاس‌پذیر برای توسعه وب مدرن فراهم می‌کند. گروه‌های مسیر یک راه‌حل زیبا برای سازماندهی کد و اعمال لایوت‌های متمایز بدون به خطر انداختن معناشناسی URL ارائه می‌دهند. مسیرهای موازی توانایی ساخت رابط‌های پویا و چند پنلی با حالت‌های مستقل را باز می‌کنند، چیزی که قبلاً فقط از طریق مدیریت حالت پیچیده سمت کلاینت قابل دستیابی بود.

با درک و ترکیب این الگوهای معماری قدرتمند، می‌توانید از وب‌سایت‌های ساده فراتر رفته و شروع به ساخت اپلیکیشن‌های پیچیده، با کارایی بالا و قابل نگهداری کنید که پاسخگوی نیازهای کاربران امروزی باشد. منحنی یادگیری ممکن است تندتر از Pages Router کلاسیک باشد، اما بازده آن از نظر معماری اپلیکیشن و تجربه کاربری بسیار زیاد است. شروع به آزمایش با این مفاهیم در پروژه بعدی خود کنید و پتانسیل کامل Next.js را باز کنید.

تسلط بر App Router در Next.js: نگاهی عمیق به معماری گروه‌های مسیر و مسیرهای موازی | MLOG