صفحهبندی و بینهایت اسکرول در Next.js: انتخاب درست بین cursor و offset
نویسنده: آرش لطیفی
کدوم صفحهبندی برای کاتالوگ فروشگاه بهتره؟ مقایسه offset، cursor و infinite scroll، پیادهسازی تمیز با Server Components و انتخاب درست بر اساس نوع داده.
TL;DR — برای کاتالوگهای بزرگ و دادههای زنده
cursorبهترینه، برای صفحات شمارهدار قابل اشتراکoffsetبذار، و بینهایت اسکرول رو فقط وقتی بچسبون که کاربر واقعاً اسکرول میکنه.
اول مسئله را درست تعریف کن
هر سه روش یک هدف رو حل میکنن: «داده بیشتری بدون ریلود کل صفحه نشون بده». تفاوتشون در تجربه کاربری و هزینه فنیه.
جدول تصمیم:
| روش | مناسب برای | مزیت | هزینه |
|---|---|---|---|
| offset (صفحه عددی) | لیستهای کمتر از ۵۰۰ آیتم | قابل اشتراک و بوکمارک، SEO خوب | آفستهای بزرگ کند میشوند |
| cursor (کلیدواژهای) | کاتالوگ بزرگ، فید زنده | سرعت ثابت در هر صفحه | URL شماره صفحه ندارد |
| Infinite scroll | فید دیجیتال، لیستهای تصویری | روان و بدون کلیک | بازگشت به عقب سخت، فوتر سنگین |
قانون سرانگشتی: اگر کاربر ممکنه بخواد به «صفحه ۴۰» لینک بده یا نتایج جستجو رو صفحه به صفحه مرور کنه، offset ببر. اگر داده مدام اضافه میشه، cursor.
پیادهسازی تمیز با Server Component
در App Router هر صفحه یک Server Component است و داده را از همانجا میگیرد. یک تابع ساده بساز که فقط داده را برگرداند:
نکته مهم: limit + 1 میگیری تا بفهمی صفحه بعدی هم هست یا نه. اگر فقط limit بگیری، آخرین صفحه را نمیفهمی و کاربر کل صفحه را اسکرول میکند تا چیزی نیاید.
بزرگترین اشتباه در این مسیر، استفاده از آفست در دیتابیس است: skip: 50000 یعنی دیتابیس ۵۰ هزار رکورد را دور میزند و تو هیچوقت روی محصول کوچک متوجه نمیشوی. cursor این را ندارد.
بینهایت اسکرول با Server Actions
برای اینکه داده در سرور بماند و فقط لیست رشد کند، یک Server Action بنویس و نتیجه را به کلاینت بفرست:
کلاینت فقط دکمه «بارگذاری بیشتر» را نگه میدارد و state را append میکند. این الگو سادهترین و قابلاعتمادترین نسخهی infinite scroll است و برای دستهبندی محصول عالی جواب میدهد.
IntersectionObserver برای اسکرول واقعی
اگر واقعاً میخواهی بدون کلیک لود شود، از IntersectionObserver استفاده کن، نه listener اسکرول. این کد کوتاهتر، دقیقتر و کممصرفتر است:
rootMargin: "400px" باعث میشود قبل از رسیدن کاربر به ته صفحه، داده بعدی آماده باشد. اگر این را صفر بگذاری، لود بعدی همیشه دیر انجام میشود و کاربر منتظر میماند.
اگر کلاینت زیاد داری، حواست به مرز 'use client' باشد؛ این مرز دقیقاً جایی است که خیلیها بخش بزرگی از باندل را کلاینت میکنند. این کامپوننت را ایزوله نگه دار.
انتخاب نهایی برای فروشگاه اینترنتی
برای بیشتر فروشگاههای فارسی:
- نتایج جستجو و دستهبندی: صفحهبندی عددی با
offset. آدرسها قابل اشتراک و قابل ایندکساند. - صفحه اصلی و دستههای کوچک: بینهایت اسکرول با دکمه بارگذاری بیشتر بهعنوان fallback برای صفحهکلید.
- سفارشها و اعلانها:
cursor.
اگر لیست را بینهایت اسکرول کردی ولی تعداد نتایج کم است، فقط UX را بدتر کردهای؛ کاربر دکمه «بعدی» را نمیبیند و فکر میکند همه را دیده.
برای بهینهسازی تصاویر لیستهای طولانی، راهنمای بهینهسازی تصویر در Next.js را بخوان. اگر همزمان روی این صفحه فیلتر و مرتبسازی داری، حواست باشد که state فیلتر را در URL نگه داری تا صفحهبندی با آن نشکند.
چکلیست
- [ ] مرتبسازی پایدار (مثلاً
createdAtبهعلاوهid) در کوئری هست - [ ] از آفستهای بزرگ در دیتابیس استفاده نشده
- [ ] برای تشخیص صفحه بعدی،
limit + 1گرفته میشود - [ ] حالت لودینگ و حالت «پایان لیست» پیاده شده
- [ ] دکمه بارگذاری بیشتر برای صفحهکلید و اسکرولنکردن کاربر هست
- [ ] دکمه «بازگشت به بالا» در حالت بینهایت اسکرول اضافه شده
سوالات پرتکرار
Q: آفست یا کورسر، کدوم سریعتره؟
هر دو سرعت یکسانی ندارند؛ آفست با بزرگ شدن شماره صفحه کند میشود چون دیتابیس رکوردهای رد شده را میخواند. cursor عملاً همیشه ثابت است.
Q: بینهایت اسکرول برای SEO بد است؟
اگر هر محصول آدرس مستقل نداشته باشد، خزنده فقط چند آیتم اول را میبیند. برای صفحات دستهبندی مهم، صفحهبندی عددی امنتر است.
Q: با فیلتر و جستجو چه کار کنم؟
فیلترها را در query string نگه دار و برای هر ترکیب فیلتر، کورسر را ریست کن. اگر کورسر را ریست نکنی، لیست نتایج اشتباه و تکراری میشود.
منابع
- پیادهسازی Infinite Scroll با Intersection Observer در freeCodeCamp — الگوی
IntersectionObserverکه در مقاله استفاده شده - گفتگوی r/nextjs دربارهی بینهایت اسکرول یا صفحهبندی برای SEO — تجربهی کامیونیتی دربارهی خزنده و صفحهبندی
- پرسش و پاسخ کورسر با Prisma و SWR — اتصال کورسر به ORM و کلاینت
- گفتگوی vercel/next.js دربارهی کورسر با رندر استاتیک — محدودیتهای کورسر در صفحات استاتیک
- مقایسهی آفست و کورسر برای توسعهدهندگان — تحلیل مستقل موازنهی دو روش