Route Parameters: خواندن بخش متغیر یک مسیر

در درس قبل با Routeهای ثابت مثل /products کار کردیم. اما بسیاری از صفحات واقعی به یک شناسه خاص وابسته‌اند؛ مثلاً صفحه جزئیات یک محصول خاص. در این درس می‌بینیم چگونه بخشی از خود مسیر را به‌عنوان یک پارامتر متغیر تعریف و در کامپوننت بخوانیم.

مشکل: یک Route جداگانه برای هر محصول؟

نوشتن یک Route مجزا برای هر محصول (/products/1، /products/2 و...) عملاً غیرممکن است؛ تعداد محصولات پویا و نامشخص است. به یک الگوی مسیر نیاز داریم که بتواند هر مقدار ممکن را در یک بخش خاص بپذیرد.

تعریف یک پارامتر با دونقطه

const router = createBrowserRouter([
  {
    path: "/",
    element: <Layout />,
    children: [
      { path: "products/:productId", element: <ProductDetail /> },
    ],
  },
]);

بخش :productId یعنی «هر مقداری اینجا باشد، آن را به‌عنوان یک پارامتر به نام productId در نظر بگیر». حالا مسیرهای /products/1، /products/42 یا /products/abc، همگی با همین یک Route تطبیق پیدا می‌کنند.

خواندن پارامتر با useParams

import { useParams } from "react-router-dom";

function ProductDetail() {
  const { productId } = useParams();
  return <p>جزئیات محصول شماره {productId}</p>;
}

useParams یک Hook است که آبجکتی از تمام پارامترهای مسیر فعلی برمی‌گرداند. اگر کاربر به /products/42 برود، مقدار productId برابر رشته "42" خواهد بود.

نکته مهم: مقدار پارامتر همیشه رشته است

حتی اگر مقدار داخل URL شبیه یک عدد به‌نظر برسد، useParams آن را همیشه به‌صورت رشته برمی‌گرداند؛ چون URL خودش ذاتاً متن است. اگر برای مقایسه یا محاسبه به عدد نیاز دارید، باید خودتان تبدیل کنید:

const id = Number(productId);

ترکیب پارامتر با دریافت داده

الگوی رایج این است که مقدار پارامتر را به یک Effect یا Custom Hook دریافت داده (که در فصل قبل ساختیم) بدهیم:

function ProductDetail() {
  const { productId } = useParams();
  const { data: product, loading } = useFetch(`/api/products/${productId}`);

  if (loading) return <p>در حال بارگذاری...</p>;
  return <h2>{product.name}</h2>;
}

چون productId به‌عنوان Dependency در Hook دریافت داده استفاده می‌شود، با تغییر مسیر از یک محصول به محصول دیگر، درخواست جدیدی خودکار ارسال می‌شود؛ درست مثل هر Dependency دیگری که در فصل ششم دیدیم.

چند پارامتر در یک مسیر

یک مسیر می‌تواند بیش از یک پارامتر داشته باشد:

{ path: "categories/:categoryId/products/:productId", element: <ProductDetail /> }
const { categoryId, productId } = useParams();

مثال قابل اجرا

در این مثال شبیه‌سازی‌شده، شناسه انتخابی به‌جای useParams، مستقیم به کامپوننت پاس داده شده تا همان رفتار خواندن پارامتر را ببینید.

شبیه‌سازی خواندن یک پارامتر مسیر
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

با گذاشتن :نام در تعریف یک مسیر، بخشی از URL به یک پارامتر متغیر تبدیل می‌شود که با useParams در کامپوننت خوانده می‌شود؛ مقدار آن همیشه رشته است. این پارامتر معمولاً به‌عنوان Dependency در دریافت داده استفاده می‌شود. در درس بعدی، با Query Parameters، یعنی بخش دیگری از URL برای داده‌های اختیاری مثل فیلتر یا صفحه‌بندی، آشنا می‌شویم.