در نکست جی اس (بهخصوص App Router در نسخههای 13+ و 15)، خیلی از خطاها و سردرگمیها به خاطر درک اشتباه از زمان آمادهشدن داده ها و محل اجرای کامپوننت هاست.

در این مقاله به ۳ سؤال مهم پاسخ میدهم:
تفاوت پارامز params و سرچ پارامز searchParams در سرور و کلاینت چیست؟
چرا searchParams به Suspense نیاز دارد ولی params نه؟
آیا میتوان از async/await در کامپوننت های کلاینتی و سروری استفاده کرد؟
پارامز (پارامها) params (Route Params)
مثال:
/products/42
export default function Page({ params }) {
console.log(params.id) // 42
}
🔹 ویژگیها:
از ساختار مسیر (folder-based routing) میآید
قبل از رندر صفحه کاملاً مشخص است
در کامپوننت سروری در دسترس است
همزمان با ساخت URL تعیین میشود
📌 نتیجه:
نکست جی اس از همان ابتدا میداند کاربر به کدام صفحه رفته است
searchParams (Query String)
مثال:
/products?page=2&sort=price
const params = useSearchParams()
params.get("page")
🔹 ویژگیها:
وابسته به URL نهایی مرورگر
بعد از navigation ممکن است هنوز resolve نشده باشد
در Client Component با useSearchParams خوانده میشود
همزمان با hydration آماده میشود، نه قبل از آن
📌 نتیجه:
نکست جی اس ممکن است صفحه را رندر کند، در حالی که search params هنوز کامل نشدهاند
دلیل اصلی: زمان آماده شدن داده
نوع داده
زمان آماده بودن
params
قبل از رندر
searchParams
بعد از hydration
چرا params امن است؟
مسیر URL بدون query ساخته نمیشود
سرور دقیقاً میداند چه صفحهای باید رندر شود
نیازی به صبر کردن نیست
// Server Component
export default async function Page({ params }) {
return <h1>{params.id}</h1>
}
چرا searchParams خطرناک است؟
در Client Component:
function CartContent() {
const params = useSearchParams()
}
در لحظهی اول:
نکست جی اس هنوز در حال استریم صفحه است
URL نهایی ممکن است هنوز کامل نباشد
ریاکت اجازه نمیدهد UI ناقص رندر شود
📌 بنابراین نکست جی اس میگوید:
«اگر چیزی به URL وابسته است، خودت مسئول صبر کردنش هستی»
و این صبر کردن فقط با Suspense انجام میشود.
<Suspense fallback={<Loading />}>
<CartContent />
</Suspense>
✅ کامپوننت های سروری — کاملاً مجاز
در کامپوننت سروری:
export default async function Page() {
const data = await fetch("https://api.example.com/data")
return <div>{data.title}</div>
}
✔️ مزایا:
رندر منتظر داده میماند
HTML نهایی با دیتا ساخته میشود
عالی برای سئو
بدون نیاز به Suspense (مگر برای Streaming)
⚠️ کامپوننت های کلاینتی — محدودیت جدی
در Client Component:
"use client"
export default async function Page() {
// ❌ خطا
}
❌ این کار ممنوع است
چرا؟
ریاکت نمیتواند رندر کامپوننت کلاینتی را با await متوقف کند
رابط کاربری UI باید فوراً رندر شود
useEffect(() => {
async function load() {
const data = await fetch(...)
setData(data)
}
load()
}, [])
مثل:
React cache
TanStack Query
SWR
async/await به عنوان ابزار
برای صبر در سرور کاربرد دارد
useEffect به عنوان ابزار
برای صبر بعد از رندر در کلاینت کاربرد دارد
Suspense به عنوان ابزار
برای توقف رندر رابط کاربری UI تا آمادهشدن شرط کاربرد دارد
📌ساسپنس Suspense جایگزین await در کلاینت است، نه fetch.
❌ اشتباه رایج
const params = useSearchParams() // بدون Suspense
✅ الگوی درست
<Suspense fallback={<Skeleton />}>
<ProductList />
</Suspense>
function ProductList() {
const params = useSearchParams()
const page = params.get("page")
}
پارامز params از مسیر میآید → قبل از رندر آماده است
سرچ پارامز searchParams از URL نهایی میآید → ممکن است دیرتر آماده شود
کامپوننت کلاینتی نمیتواند async باشد
ساسپنس Suspense راه استاندارد نکست جی اس برای صبر کردن در کلاینت است
ای سینک و یا اویت async/await ابزار سرور است، نه کلاینت
آیا useSearchParams همیشه نیاز به Suspense دارد؟
بله، اگر داخل کامپوننت کلاسنتی استفاده شود.
چرا نکست جی اس این محدودیت را گذاشته؟
برای استریمینگ، کارایی و جلوگیری از خطای Hydration .
بهترین روش خواندن search params برای سئو چیست؟
در کامپوننت سروری با searchParams prop.