Routing در اکوسیستم React

در فصل پانزدهم، Routing را با React Router یاد گرفتیم: تعریف Routeها، Nested Routes، پارامترهای مسیر و Query، ناوبری و Protected Routes. اما React خودش هیچ سیستم Routing ندارد. این یک انتخاب اکوسیستمی است، و جواب آن به ابزارهایی که در درس قبل دیدیم (Framework یا Build Tool) وابسته است. این درس نقشه آن انتخاب‌ها را می‌کشد.

یک تصحیح مهم نسبت به فصل ۱۵

در درس‌های فصل پانزدهم، همه APIها را از بسته react-router-dom import کردیم. React Router نسخه ۸ در ژوئن ۲۰۲۶ منتشر شد و این بسته را حذف کرد؛ در نسخه ۷ فقط یک بسته سازگارکننده بود که همان APIها را دوباره Export می‌کرد. قاعده جدید، طبق مستندات رسمی:

  • تقریباً همه چیز (مثل createBrowserRouter، Link، NavLink، Outlet، useParams، useNavigate، Navigate و useSearchParams) از react-router وارد می‌شود.
  • APIهای مخصوص DOM، مثل RouterProvider (و HydratedRouter در حالت Framework)، از react-router/dom وارد می‌شوند.
jsx
// فصل ۱۵ (نسخه ۷ و قدیمی‌تر)
import { createBrowserRouter, RouterProvider } from "react-router-dom";

// نسخه ۸
import { createBrowserRouter } from "react-router";
import { RouterProvider } from "react-router/dom";

مفاهیم آن فصل تغییری نکرده‌اند؛ فقط مسیر importها عوض شده. اگر کدی با react-router-dom دیدید، احتمالاً مربوط به نسخه ۷ یا قدیمی‌تر است. نسخه ۸ حداقل‌های جدیدی هم دارد: Node نسخه ۲۲٫۲۲ یا بالاتر، React نسخه ۱۹٫۲٫۷ یا بالاتر و (برای حالت Framework) Vite نسخه ۷ یا بالاتر. چون نسخه‌ها سریع عوض می‌شوند، پیش از شروع پروژه، مستندات رسمی را بررسی کنید.

سه جایگاه ممکن برای Routing

Routing می‌تواند در یکی از سه سطح باشد، و هرکدام سطح متفاوتی از کار را به عهده خودتان یا ابزار می‌گذارند:

  • کتابخانه Routing در یک SPA: یک Build Tool (مثل Vite) به‌علاوه یک کتابخانه Routing. تصمیم Routing، دریافت داده و Code Splitting با خودتان است.
  • Routing مبتنی بر ساختار فایل‌ها: ساختار پوشه‌ها و فایل‌ها تعیین می‌کند چه آدرس‌هایی وجود دارند. Next.js App Router نمونه رایج آن است.
  • Routing یکپارچه با Framework: Routing، دریافت داده، رندر سرور و Build در یک بسته. React Router در حالت Framework و TanStack Start از این دسته‌اند.

React Router: یک کتابخانه، سه حالت

از نسخه ۷، React Router در سه حالت عرضه می‌شود:

  • Declarative: ساده‌ترین حالت برای SPA؛ همان BrowserRouter، Routes و Route.
  • Data: همان Declarative به‌علاوه ابزارهای دریافت و ارسال داده در سطح Route، مثل Loader و Action. این همان حالتی است که در فصل ۱۵ با createBrowserRouter استفاده کردیم.
  • Framework: Data به‌علاوه یک خط Build مبتنی بر Vite، رندر سرور و تنظیمات اضافه. استفاده از Routing مبتنی بر ساختار فایل‌ها در آن اختیاری است.

مثال: Loader در حالت Data

تفاوت بزرگ این حالت با فصل ۱۵، این است که داده می‌تواند به خود Route وصل شود:

jsx
import { createBrowserRouter, useLoaderData } from "react-router";
import { RouterProvider } from "react-router/dom";

async function productLoader({ params }) {
  const res = await fetch(`/api/products/${params.id}`);
  return res.json();
}

function Product() {
  const product = useLoaderData();
  return <h2>{product.name}</h2>;
}

const router = createBrowserRouter([
  {
    path: "/products/:id",
    element: <Product />,
    loader: productLoader,
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

Loader در زمان ناوبری، پیش از Render شدن کامپوننت Route اجرا می‌شود (و برای Routeهای تودرتو معمولاً به‌صورت موازی). این همان الگوی Render-as-you-fetch است که در درس ۱۴-۸ در برابر Fetch-on-render معرفی کردیم: درخواست داده دیگر منتظر Mount شدن کامپوننت و اجرای useEffect نمی‌ماند.

Routing مبتنی بر ساختار فایل‌ها

در این سبک، به‌جای نوشتن فهرست Routeها در کد، پوشه‌ها و فایل‌ها آن‌ها را تعریف می‌کنند. مثال از قرارداد Next.js App Router:

html
app/
  layout.js            ← Layout مشترک
  page.js              ← آدرس /
  products/
    page.js            ← آدرس /products
    [id]/
      page.js          ← آدرس /products/:id

نام‌هایی مثل page.js، layout.js و پوشه [id] قرارداد همان Framework هستند، نه بخشی از React. این ساختار، همان مفاهیم فصل ۱۵ را به شکل دیگری بیان می‌کند: پوشه [id] معادل :id در مسیر است، و layout.js معادل Layoutی که با Outlet فرزندش را نشان می‌دادیم. برای بسیاری از موارد دیگر (مثل Loading و Error)، Frameworkهایی از این دست، فایل‌های قراردادی دارند که پشت صحنه از Suspense و Error Boundary همین دوره استفاده می‌کنند (درس‌های ۲۱ و ۱۷).

چه چیزی با یکپارچگی Routing و Framework تغییر می‌کند

  • Code Splitting خودکار: در فصل‌های ۱۵ و ۲۰ خودمان lazy و Suspense را دور هر Route می‌گذاشتیم. در Frameworkها، تقسیم کد بر اساس Route معمولاً به‌صورت پیش‌فرض انجام می‌شود.
  • دریافت داده متصل به Route: داده Route مشخص و پیش از Render شروع می‌شود (Loader یا Server Component).
  • Layoutهای تودرتو مفهومی اصلی هستند: نه یک الگوی ساخته‌شده با Outlet توسط خودمان.
  • Streaming و مرزهای Route: همان چیزی که در درس ۲۴-۷ دیدیم، با مرز Route هماهنگ می‌شود.

گزینه‌های دیگر

TanStack Router یک کتابخانه Routing است که تمرکز اصلی آن روی ایمنی نوع (Type Safety) در مسیرها و پارامترهاست، و TanStack Start روی آن یک Framework Full-stack می‌سازد. Expo Router همان ایده Routing مبتنی بر ساختار فایل‌ها را برای برنامه‌های موبایل با React Native می‌آورد. اگر مسیر تکنولوژی شما یکی از این‌هاست، مستندات همان ابزار را بخوانید؛ جزئیات APIهای آن‌ها فراتر از این دوره است.

چگونه انتخاب کنیم

  • نیاز به رندر سرور یا SEO دارید؟ Routing یکپارچه با یک Framework معمولاً مناسب‌تر است.
  • SPA ساده یا ابزار داخلی دارید؟ Build Tool به‌علاوه React Router در حالت Declarative یا Data معمولاً کافی است.
  • تیم با کدام ابزار آشناست؟ هزینه یادگیری و مهاجرت، بخش واقعی این تصمیم است.
  • Routing را جدا از بقیه تصمیم نگیرید: انتخاب Routing معمولاً با انتخاب Framework و روش دریافت داده گره خورده است.

دریافت داده و Server State در درس بعد، و مقایسه Library و Framework در درس ۲۵-۸ ادامه پیدا می‌کنند.

چرا این درس مثال قابل اجرا ندارد

ویرایشگر درون‌صفحه‌ای بسته‌های Router و ساختار پروژه Framework را ندارد. برای اجرا، یک پروژه واقعی با نسخه مناسب بسازید.

جمع‌بندی

Routing جزو خود React نیست و در اکوسیستم، از یک کتابخانه روی Build Tool تا Routing مبتنی بر ساختار فایل‌ها و Routing یکپارچه با Framework، سطوح مختلفی دارد. React Router در سه حالت Declarative، Data و Framework عرضه می‌شود، و از نسخه ۸ (ژوئن ۲۰۲۶) بسته react-router-dom حذف شده است: APIها از react-router و RouterProvider از react-router/dom وارد می‌شود. هرچه Routing به Framework نزدیک‌تر باشد، دریافت داده، Code Splitting و Layoutهای تودرتو بیشتر به‌صورت خودکار به Route وصل می‌شوند. در درس بعدی، به دریافت داده و Server State در اکوسیستم می‌پردازیم.