কার্সার পেজিনেশন ডেটা পরিবর্তিত হলে তালিকাকে স্থির রাখে। জানুন কেন ইনসার্ট ও ডিলিট হলে অফসেট পেজিং ভেঙে পড়ে, এবং কীভাবে পরিষ্কার কার্সার বাস্তবায়ন করবেন।

আপনি একটি ফিড খুললেন, একটু স্ক্রল করলেন, এবং সবকিছু স্বাভাবিক মনে হলো যতক্ষণ না সেটা হয় না। আপনি একই আইটেম দুবার দেখেন। যা আপনি নিশ্চিতভাবে দেখেছিলেন সেটা হারিয়ে গেছে। একটি সারি আপনি ট্যাপ করতে যাচ্ছিলেন হঠাৎ নিচে সরে যায়, এবং আপনি ভুল ডিটেইল পেজে পৌঁছান।
এগুলো ব্যবহারকারীর দেখা যায় এমন বাগ, যদিও আপনার API রেসপন্স আলাদাভাবে “ঠিক” দেখায়। সাধারণ লক্ষণগুলো সহজে চেনা যায়:
মোবাইলের উপর এটি আরও খারাপ হয়ে যায়। মানুষ থামে, অ্যাপ বদলায়, কানেক্টিভিটি হারায়, পরে চালিয়ে দেয়। সেই সময়ে নতুন আইটেম আসে, পুরোনোগুলো মুছে ফেলা হয়, এবং কিছু এডিট হয়। যদি আপনার অ্যাপ page 3-এর জন্য অফসেট ব্যবহার করে বারবার অনুরোধ করে, পেজ বাউন্ডারিগুলো ব্যবহারকারীর মাঝখানে বদলে যেতে পারে। ফলাফল: একটি ফিড যা অস্থির এবং অবিশ্বাস্য মনে হয়।
লক্ষ্য সোজা: একবার ব্যবহারকারী সামনে স্ক্রল শুরু করলে, তালিকাটি একটি স্ন্যাপশটের মতো আচরণ করা উচিত। নতুন আইটেম থাকতে পারে, কিন্তু সেগুলো ব্যবহারকারী ইতিমধ্যে পাতানো আইটেমগুলোকে পুনরায় সাজাতে পারবেনা। ব্যবহারকারী একটি মসৃণ, পূর্বানুমেয় ক্রম পাবে।
কোনো পেজিনেশন পদ্ধতি নিখুঁত নয়। বাস্তব সিস্টেমে একসঙ্গে লেখালেখি, এডিট, এবং একাধিক সোর্ট অপশন থাকে। কিন্তু কার্সার পেজিনেশন সাধারণত অফসেট পেজিনেশনের থেকে নিরাপদ, কারণ এটি একটি স্থির ক্রমে নির্দিষ্ট অবস্থান থেকে পেজ করে, পরিবর্তনশীল সারি গণনা থেকে নয়।
অফসেট পেজিনেশন হচ্ছে “skip N, take M” উপায়। আপনি API-কে বলেন কতগুলো আইটেম স্কিপ করতে (offset) এবং কতগুলো ফিরিয়ে দিতে (limit)। limit=20 থাকলে প্রতি পেজে 20টি আইটেম পাবেন।
ধারণাগতভাবে:
GET /items?limit=20&offset=0 (প্রথম পেজ)GET /items?limit=20&offset=20 (দ্বিতীয় পেজ)GET /items?limit=20&offset=40 (তৃতীয় পেজ)রেসপন্স সাধারণত আইটেমগুলো এবং পরবর্তী পেজের যথেষ্ট তথ্য দেয়।
{
"items": [
{"id": 101, "title": "..."},
{"id": 100, "title": "..."}
],
"limit": 20,
"offset": 20,
"total": 523
}
এটি জনপ্রিয় কারণ এটি টেবিল, অ্যাডমিন লিস্ট, সার্চ রেজাল্ট, এবং সহজ ফিডের সঙ্গে সুন্দরভাবে মানায়। SQL-এ LIMIT এবং OFFSET দিয়ে এটি বাস্তবে সহজে বাস্তবায়ন করা যায়।
কিন্তু সমস্যাটি হলো লুকানো অনুমান: ডেটাসেটটি ইউজার পেজিং করার সময় স্থির থাকে। বাস্তব অ্যাপে নতুন সারি ইনসার্ট হয়, সারি ডিলিট হয়, এবং সোর্ট কী বদলে যায়। এখানেই “গোপন বাগ” শুরু হয়।
অফসেট পেজিনেশন ধরে নেয় যে অনুরোধগুলোর মধ্যে তালিকাটি স্থির আছে। কিন্তু বাস্তব তালিকাগুলো সরতে পারে। যখন তালিকা সরে যায়, skip 20-এর মত অফসেট আর একই আইটেমগুলোকে নির্দেশ করে না।
ধরুন একটি ফিড created_at desc (নতুনগুলো উপরে), পেজ সাইজ 3।
আপনি offset=0, limit=3 দিয়ে পেজ 1 লোড করেন এবং পান [A, B, C]।
এখন একটি নতুন আইটেম X তৈরি হয় এবং উপরে দেখা যায়। তালিকাটি এখন [X, A, B, C, D, E, F, ...]। আপনি offset=3, limit=3 দিয়ে পেজ 2 লোড করেন। সার্ভার [X, A, B] স্কিপ করে এবং [C, D, E] ফেরত দেয়।
আপনি právě C আবার দেখেছেন (একই আইটেম ডুপ্লিকেট), এবং পরে আপনি একটি আইটেম মিস করবেন কারণ সবকিছু নিচে সরে গেছে।
ডিলিটগুলো ঠিক উল্টো ব্যর্থতা তৈরি করে। শুরুতে [A, B, C, D, E, F, ...] আছে। আপনি পেজ 1 লোড করে দেখলেন [A, B, C]। পেজ 2 নেওয়ার আগেই B ডিলিট হলে তালিকাটি হয় [A, C, D, E, F, ...]। offset=3 দিয়ে পেজ 2 তখন [A, C, D] স্কিপ করে [E, F, G] ফেরত দেয়। D হয়ে যায় একটি গ্যাপ যা আপনি কখনো ফেচ করবেন না।
নিউইস্ট-ফার্স্ট ফিডে ইনসার্টগুলো উপরে হয়, যা ঠিকই পরে থাকা প্রতিটি অফসেটকে সরিয়ে দেয়।
"স্থিতিশীল তালিকা" হচ্ছে ব্যবহারকারীরা যা আশা করে: তারা সামনে স্ক্রল করলে আইটেমগুলো ঝাঁপায় না, পুনরাবৃত্তি হয় না, বা অকারণে অদৃশ্য হয় না। এটি সময় ফ্রিজ করার বিষয় নয়, বরং পেজিংকে পূর্বানুমেয় করা।
দুইটি ধারণা প্রায়ই একসাথে মিশে যায়:
created_at এবং একটি টাই-ব্রেকার যেমন id) যাতে একই ইনপুটে দুইটি রিকোয়েস্টই একই অর্ডার ফেরত দেয়।রিফ্রেশ এবং স্ক্রল-ফরওয়ার্ড আলাদা অ্যাকশন। রিফ্রেশ মানে "এখন কী নতুন আছে তা দেখাও", তাই টপ বদলে যেতে পারে। স্ক্রল-ফরওয়ার্ড মানে "আমি যেখানে ছিলাম সেখানে থেকে চলি", তাই আপনি শিফট হওয়া পেজ বাউন্ডারি থেকে উত্পন্ন পুনরাবৃত্তি বা গ্যাপ দেখতে পাবেন না।
একটি সহজ নিয়ম যা বেশিরভাগ পেজিনেশন বাগ প্রতিরোধ করে: সম্মুখে স্ক্রল করার সময় কখনোই পুনরাবৃত্তি দেখানো উচিত নয়।
কার্সার পেজিনেশন একটি বুকমার্ক ব্যবহার করে তালিকা থেকে এগোয়, পেজ নম্বর না দিয়ে। ক্লায়েন্ট বলে “এখান থেকে চালিয়ে যাও।”
চুক্তি সরল:
এটি ইনসার্ট ও ডিলিটকে ভালভাবে সহন করে কারণ কার্সার একটি স্থির ক্রমে কোনো অবস্থানকে অ্যাংকর করে, সারি গণনা থেকে নয়।
অবশ্যই একটি অনিচ্ছেদযোগ্য শর্ত হলো নির্ধারিত ও স্থায়ী সোর্ট অর্ডার থাকা। যদি সোর্ট ডিটারমিনিস্টিক না হয় এবং টাই-ব্রেকার না থাকে, তাহলে কার্সার নির্ভরযোগ্য বুকমার্ক হবে না।
শুরুতে এমন একটি সোর্ট অর্ডার বেছে নিন যা মানুষ কীভাবে তালিকা পড়ে তার সঙ্গে মিল রাখে। ফিড, মেসেজ, এবং অ্যাক্টিভিটি লগ সাধারণত newest-first। ইতিহাসভিত্তিক তালিকা (ইনভয়েস, অডিট লগ) প্রায়ই oldest-first ভাল হয়।
কার্সারকে অবশ্যই ঐ ক্রমে একটি অবস্থান ইউনিকভাবে শনাক্ত করতে হবে। যদি দুইটি আইটেম একই কার্সার ভ্যালু শেয়ার করে, আপনি অবশেষে ডুপ্লিকেট বা গ্যাপ পাবেন।
সাধারণ পছন্দ ও সতর্কতা:
created_at: সহজ, কিন্তু অনিরাপদ যদি অনেক রো একটাই টাইমস্ট্যাম্প শেয়ার করে।id: নিরাপদ যদি ID গুলো মনোটোনিক হয়, তবে হয়ত পণ্য-চাহিদার অর্ডারের সাথে মিলে না।created_at + id: সাধারণত সবচেয়ে ভাল মিশ্রণ (টাইমস্ট্যাম্প পণ্য-কেন্দ্রিক অর্ডার দেয়, id টাই-ব্রেকার হিসেবে)।updated_at: ইনফিনাইট স্ক্রলের জন্য ঝুঁকিপূর্ণ কারণ এডিট হলে আইটেম পেজগুলোর মধ্যে সরতে পারে।যদি আপনি একাধিক সোর্ট অপশন প্রদান করেন, প্রতিটি সোর্ট মোডকে আলাদা তালিকা হিসেবে বিবেচনা করুন এবং প্রতিটির জন্য আলাদা কার্সার নিয়ম রাখুন। একটি কার্সার কেবল একটি নির্দিষ্ট অর্ডারিংয়ের জন্যই অর্থবহ।
API-ইনটারফেস ছোট রাখা যায়: দুইটি ইনপুট, দুইটি আউটপুট।
limit (কতটি আইটেম চান) এবং ঐচ্ছিক cursor (কোথা থেকে চালিয়ে যেতে) পাঠান। যদি কার্সার না থাকে, সার্ভার প্রথম পেজ ফিরিয়ে দেবে।
উদাহরণ অনুরোধ:
GET /api/messages?limit=30&cursor=eyJjcmVhdGVkX2F0IjoiMjAyNi0wMS0xNlQxMDowMDowMFoiLCJpZCI6Ijk4NzYifQ==
আইটেমগুলো এবং একটি next_cursor ফেরত দিন। যদি আর পরবর্তী পেজ না থাকে, next_cursor: null ফেরত দিন। ক্লায়েন্ট কার্সারকে একটি টোকেন হিসেবে আচরণ করবে, সম্পাদনা করবে না।
{
"items": [ {"id":"9876","created_at":"2026-01-16T10:00:00Z","subject":"..."} ],
"next_cursor": "...",
"has_more": true
}
সার্ভার-সাইড লজিক সাধারণ ভাষায়: একটি স্থির অর্ডারে সোর্ট করুন, কার্সার ব্যবহার করে ফিল্টার করুন, তারপর limit প্রয়োগ করুন।
উদাহরণসরূপ, যদি আপনি (created_at DESC, id DESC) অনুযায়ী newest first সোর্ট করেন, কার্সারকে (created_at, id) এ ডিকোড করুন, তারপর সেই কার্সার জোড়ার থেকে কড়া প্রশ্রয়ের শর্ত প্রয়োগ করে সারি সংগ্রহ করুন এবং একই অর্ডার বজায় রেখে limit নিন।
কার্সারকে base64 JSON ব্লব হিসেবে এনকোড করা যায় (সহজ) বা সাইন/এনক্রিপট করা টোকেন হিসেবে রাখা যায় (আরো কাজ)। অপ্যাক নিরাপদ কারণ এতে আপনি পরে ইন্টারনাল বদল করলে ক্লায়েন্ট ভাঙবে না।
সঙ্গে কিছু যুক্তিসঙ্গত ডিফল্ট সেট করুন: মোবাইলের জন্য সাধারণত 20–30, ওয়েবের জন্য প্রায় 50, এবং একটি সার্ভার-ম্যাক্স যাতে কোনো বাগধরা ক্লায়েন্ট 10,000 সারি চাইতে না পারে।
একটি স্থির ফিড মূলত একটি অঙ্গীকার সম্পর্কে: একবার ব্যবহারকারী সামনে স্ক্রল শুরু করলে, তারা দেখা না করা আইটেমগুলো অন্য কারো দ্বারা তৈরি, মুছে বা সম্পাদিত হওয়ার কারণে লাফাবে না।
কার্সার পেজিনেশনে ইনসার্ট সবচেয়ে সহজ। নতুন রেকর্ডগুলি রিফ্রেশে দেখানো উচিত, ইতিমধ্যে লোড করা পেজগুলোর মধ্যে নয়। যদি আপনি (created_at DESC, id DESC) অর্ডার করুন, নতুন আইটেমগুলো স্বাভাবিকভাবেই প্রথম পেজের আগে থাকবে, তাই আপনার বিদ্যমান কার্সার পুরোনো আইটেমের দিকে চালিয়ে যাবে।
ডিলিটগুলো তালিকাকে পুনরায় সাজাবে না। যদি একটি আইটেম ডিলিট হয়, তখন এটি সহজেই না ফেরত দেওয়া হবে যখন আপনি সেটি ফেচ করতেন। পেজ সাইজ ধরে রাখতে চাইলে দেখা হওয়া limit দৃশ্যমান আইটেম সংগ্রহ না হওয়া পর্যন্ত ফেচ চালিয়ে যান।
এডিট হল যেখানে দলগুলি ভুলবশত বাগ পুনরায় নিয়ে আসে। মূল প্রশ্ন: একটি এডিট কি সোর্ট পজিশন বদলে দিতে পারে?
স্ক্রলিং তালিকার জন্য সাধারণত স্ন্যাপশট-স্টাইল আচরণ ভাল: created_at মত একটি অপরিবর্তনীয় কী দিয়ে পেজউইজ করা। এডিট কন্টেন্ট পরিবর্তন করতে পারে, কিন্তু আইটেম নতুন অবস্থানে ঝাঁপাবে না।
লাইভ-ফিড আচরণ যদি edited_at দিয়ে সোর্ট করে; এটার ফলে আইটেমগুলো পেজগুলোর মধ্যে সরতে পারে। যদি আপনি এটি বেছে নেন, তবে তালিকাকে ক্রমাগত পরিবর্তনশীল হিসেবে ধরুন এবং UX-টা রিফ্রেশকে কেন্দ্র করে ডিজাইন করুন।
কার্সারকে “এই নির্দিষ্ট রোটি খুঁজে পাও”র ওপর নির্ভর করে বানাবেন না। অবস্থান এনকোড করুন, যেমন {created_at, id} যা শেষ ফেরত আইটেমের। তারপর পরবর্তী কুয়েরি মানভিত্তিক হবে:
WHERE (created_at, id) < (:created_at, :id)id) অন্তর্ভুক্ত করুন যাতে ডুপ্লিকেট এড়ায়ফরওয়ার্ড পেজিং সহজ অংশ। সমস্যা জায়গাগুলো হচ্ছে ব্যাকওয়ার্ড পেজিং, রিফ্রেশ, এবং র্যান্ডম অ্যাক্সেস।
ব্যাকওয়ার্ড পেজিংয়ের জন্য দুইটি পদ্ধতি কাজ করে:
next_cursor পুরোনো আইটেমের জন্য এবং prev_cursor নতুন আইটেমের জন্য) কিন্তু স্ক্রিনে একরকম সোর্ট অর্ডার রাখুন।র্যান্ডম লাফ কার্সারের সঙ্গে কঠিন কারণ “পেজ 20” এর একটি স্থির অর্থ থাকে না যখন তালিকা পরিবর্তিত হয়। যদি সত্যিই লাফ দরকার হয়, একটি অ্যাঙ্কারের দিকে লাফ দিন—যেমন “এই টাইমস্ট্যাম্পের চারপাশে” বা “এই মেসেজ id থেকে শুরু করে” — পেজ ইনডেক্স নয়।
মোবাইলে ক্যাশিং গুরুত্বপূর্ণ। প্রতিটি লিস্ট স্টেট (কোয়েরি + ফিল্টার + সোর্ট) অনুযায়ী কার্সার সংরক্ষণ করুন, এবং প্রতিটি ট্যাব/ভিউকে আলাদা তালিকা হিসেবে আচরণ করুন। এতে “ট্যাব বদলে দিলে সবকিছু এলোমেলো হয়ে যায়” সমস্যা রোধ করা যায়।
অধিকাংশ কার্সার পেজিনেশন ইস্যু ডেটাবেস-সম্পর্কিত নয়। এগুলো ছোট অসামঞ্জস্য থেকে আসে যা কেবল বাস্তব ট্র্যাফিকে প্রকাশ পায়।
সবচেয়ে বড় ভুলগুলো:
created_at) ফলে টাই ঘটলে ডুপ্লিকেট বা মিসিং আইটেম হয়।next_cursor ফেরত দেওয়া যা প্রকৃতপক্ষে শেষ ফেরত দেওয়া রো-এর সঙ্গে মিল নেই।আপনি যদি Koder.ai-র মতো প্ল্যাটফর্মে অ্যাপ বানান, এই এজ কেসগুলো দ্রুত দেখা যায় কারণ ওয়েব ও মোবাইল ক্লায়েন্ট প্রায়ই একই এন্ডপয়েন্ট শেয়ার করে। একটি স্পষ্ট কার্সার কনট্রাক্ট এবং নির্ধারিত অর্ডারিং রুল থাকা উভয় ক্লায়েন্টকে সঙ্গত রাখে।
পেজিনেশনকে “করা হয়েছে” বলা কেওয়ালে না, ইনসার্ট, ডিলিট এবং রিট্রাইটের অধীনে আচরণ যাচাই করে নিন।
next_cursor শেষ ফেরত রো থেকে নেওয়াlimit-এর একটি নিরাপদ ম্যাক্স এবং ডকুমেন্টেড ডিফল্ট আছেরিফ্রেশের জন্য একটি পরিচ্ছন্ন নিয়ম নিন: বা ব্যবহারকারীরা পুল-টু-রিফ্রেশ করে টপে নতুন আইটেম আনবে, অথবা আপনি সময়ে সময়ে “আমার প্রথম আইটেমের চেয়ে নতুন কিছু আছে?” চেক করে একটি “New items” বাটন দেখাবেন। ধারাবাহিকতা হল যা তালিকাকে haunted মনে হওয়ার বদলে স্থিতিশীল করে।
একটি সাপোর্ট ইনবক্স কল্পনা করুন যা এজেন্টরা ওয়েবে ব্যবহার করে, এবং ম্যানেজার একই ইনবক্স মোবাইলে চেক করে। তালিকা newest-first। প্রত্যাশা স্পষ্ট: যখন তারা সামনে স্ক্রল করে, আইটেমগুলো ঝাঁপে না, পুনরাবৃত্তি হয় না, বা অদৃশ্য হয় না।
অফসেট পেজিংয়ে, একজন এজেন্ট পেজ 1 (আইটেম 1–20) লোড করে, তারপর পেজ 2 (offset=20) তে যায়। তারা পড়ার সময় উপরে দুইটি নতুন মেসেজ আসে। এখন offset=20 তার আগের মানের থেকে ভিন্ন জায়গা নির্দেশ করে। ব্যবহারকারী ডুপ্লিকেট দেখেন বা মিস করেন।
কার্সার পেজিনেশনে, অ্যাপ “এই কার্সারের পরে পরবর্তী 20 আইটেম” চাইবে, যেখানে কার্সারটি ব্যবহারকারী প্রকৃতপক্ষে শেষ দেখা আইটেমের উপর ভিত্তি করে (সাধারণত (created_at, id))। নতুন মেসেজ সারাদিন আসতে পারে, কিন্তু পরবর্তী পেজ তবু শেষ দেখা মেসেজের ঠিক পর থেকেই শুরু হবে।
শিপ করার আগে একটি সহজ পরীক্ষা:
প্রোটোটাইপ দ্রুত করতে চাইলে, Koder.ai আপনাকে চ্যাট প্রম্পট থেকে এন্ডপয়েন্ট ও ক্লায়েন্ট ফ্লো স্ক্যাফোল্ড করতে সাহায্য করতে পারে, তারপর Planning Mode প্লাস স্ন্যাপশট ও রোলব্যাক ব্যবহার করে নিরাপদে ইটারেট করুন যখন পেজিনেশন পরিবর্তন টেস্টে আপনাকে আচমকা অপ্রত্যাশিত ফল দেয়।
অফসেট পেজিনেশন হল “Nটি সারি স্কিপ করো” পদ্ধতি, তাই যদি নতুন সারি ইনসার্ট হয় বা পুরোনো সারি মুছে ফেলা হয়, সারির গণনা সরতে পারে। একই offset হঠাৎ ভিন্ন আইটেমকে নির্দেশ করতে পারে, ফলে ব্যবহারকারীরা স্ক্রলের মধ্যে পুনরাবৃত্তি বা গ্যাপ দেখতে পান।
কার্সার পেজিনেশন একটি বুকমার্ক ব্যবহার করে যা “আমি যে শেষ আইটেমটি দেখেছি তার পরে” অবস্থানকে প্রতিনিধিত্ব করে। পরবর্তী অনুরোধ সেই অবস্থান থেকে নির্দিষ্ট ও স্থায়ী ক্রমে চালিয়ে যায়, তাই টপ-এ ইনসার্ট বা মাঝখানে ডিলিট হওয়া আইটেম আপনার পেজ বাউন্ডারি একইভাবে সরায় না।
একটি নির্দিষ্ট এবং ইউনিক টাই-ব্রেকার সহ একটি নির্ধারিত সোর্ট ব্যবহার করুন; সাধারণত (created_at, id) সবচেয়ে ভাল মিশ্রণ। created_at প্রোডাক্ট-ফ্রেন্ডলি অর্ডার দেয়, এবং id প্রতিটি অবস্থানকে ইউনিক করে তোলে যাতে টাইমস্ট্যাম্প সיהם হলে আপনি আইটেম পুনরাবৃত্তি বা স্কিপ না করুন।
updated_at-এর উপর সোর্ট করা তখন সমস্যা তৈরি করতে পারে যখন আইটেম এডিট হওয়ার ফলে পেজে তার অবস্থান বদলে যায়—এটি “স্টেবল স্ক্রোল ফরওয়ার্ড” প্রত্যাশাকে ভেঙে দেয়। যদি আপনাকে লাইভ “সর্বশেষ আপডেট” ভিউ দরকার হয়, তাহলে UI-কে রিফ্রেশ ডিজাইন করে পুনরায় অর্ডারিং গ্রহণ করার মতোভাবে বানান।
একটি opaque টোকেন next_cursor হিসেবে ফিরিয়ে দেবেন এবং ক্লায়েন্ট সেটি অপরিবর্তিতভাবে ফেরত পাঠাবে। সহজ উপায় হচ্ছে শেষ আইটেমের (created_at, id)-কে base64 JSON ব্লব হিসেবে এনকোড করা, তবে তা একটি অপাক ভ্যালু হিসেবে আচরণ করানোই গুরুত্বপূর্ণ যাতে ভবিষ্যতে ইন্টারনাল বদল করলে ক্লায়েন্ট ব্রেক না করে।
কার্সার ভেলু নির্ভর করে ‘এই সুনির্দিষ্ট রো’ খুঁজে পাওয়ার ওপর তৈরি করবেন না। বরং অবস্থান এনকোড করুন, যেমন শেষ ফেরত দেওয়া আইটেমের {created_at, id}। এরপর পরবর্তি কোয়েরি মানভিত্তিক হবে, না যে রোটি এখন আর আছে কি না- তাতে নয়।
কঠোর তুলনা ব্যবহার করুন এবং একটি ইউনিক টাই-ব্রেকার রাখুন, এবং সব সময় next_cursor নেবেন যেটা প্রকৃতপক্ষে শেষ ফেরত দেওয়া রো থেকে নেওয়া হয়েছে। বেশিরভাগ পুনরাবৃত্তি ত্রুটি হয় <= ব্যবহার করার কারণে, টাই-ব্রেকার না রাখার কারণে, বা ভুল রো থেকে next_cursor তৈরির কারণে।
স্পষ্ট একটি নিয়ম বেছে নিন: রিফ্রেশ টপে নতুন আইটেম লোড করে, আর স্ক্রোল-ফরওয়ার্ড বিদ্যমান কার্সার থেকে পুরোনো আইটেমের দিকে চালিয়ে যায়। রিফ্রেশ সেমানটিক্সকে একই কার্সার ফ্লোর সঙ্গে মিশাবেন না, না হলে ব্যবহারকারী রি-অর্ডারিং দেখে লিস্ট অপ্রত্যাশিত মনে করবে।
একটি কার্সার কেবল একটি সুনির্দিষ্ট অর্ডার ও ফিল্টার সেটের জন্যই মান্য। যদি ক্লায়েন্ট সোর্ট মোড, সার্চ কোয়েরি বা ফিল্টার পরিবর্তন করে, তাহলে মাথা ন্যূনশর্ত ছাড়া নতুন পেজিনেশন সেশান শুরু করতে হবে এবং আলাদা লিস্ট স্টেটের জন্য আলাদা কার্সার সংরক্ষণ করতে হবে।
কার্সার পেজিনেশন ধারাবাহিক ব্রাউজিংয়ের জন্য চমৎকার, তবে “পেজ ২০” ধরনের স্থির লাফের জন্য উপযুক্ত নয় কারণ ডেটাসেট পরিবর্তিত হতে পারে। যদি লাফ দরকার হয়, তাহলে একটি অ্যাঙ্কর-এ লাফ দিন—যেমন “এই টাইমস্ট্যাম্পের চারপাশে” বা “এই id-এর পরে শুরু করে”—তারপর সেখান থেকে কার্সার দিয়ে পেজিনেট করুন।