like-gold•1h ago
Cursor Pagination with useInfiniteList in Refine: Still Not Working - Need Help!
I've been stuck on this for days now, and I'm at my wit's end. I'm trying to implement
infinite scrolling in a chat application using Refine's useInfiniteList, but the cursor
pagination simply refuses to work properly. If anyone has successfully implemented this,
please help!
What I'm Trying to Do
I'm building a WhatsApp-like chat interface where messages should load incrementally as the
user scrolls up. Sounds simple enough, right? But the cursor from getNextPageParam is NOT
reaching my data provider correctly.
The Problem
Here's what's happening - my frontend code with useInfiniteList:
const {
data: messagePages,
fetchNextPage,
hasNextPage,
} = useInfiniteList({
resource: "whatsapp/messages",
pagination: { pageSize: 25 },
queryOptions: {
getNextPageParam: (lastPage) => {
console.log("Last page received:", lastPage);
console.log("Cursor next:", lastPage?.cursor?.next);
// This shows the cursor perfectly!
return lastPage?.cursor?.next
? JSON.stringify(lastPage.cursor.next)
: undefined;
},
},
});
The console shows:
Last page received: {data: Array(25), cursor: {next: {id: "msg_123", timestamp:
1234567890}}}
Cursor next: {id: "msg_123", timestamp: 1234567890}
Great! But then in my data provider:
getList: async ({ resource, pagination, filters, sorters, meta }) => {
console.log("[DataProvider] Received pagination:", pagination);
// This prints: {currentPage: 1, pageSize: 25, mode: "server"}
// WHERE IS MY CURSOR?! 😭
}
What I've Already Tried
4 Replies
Hi @Martola. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
like-goldOP•1h ago
Attempt 1: Following the Documentation
The Refine docs mention cursor pagination but the examples don't actually show how the
cursor gets passed to the data provider. The GitHub examples seem broken too (found an issue
from March 2024 about this).
Attempt 2: Checking Different Properties
I've tried checking every possible property:
const { currentPage, pageSize } = pagination ?? {};
console.log("currentPage type:", typeof currentPage); // Always "number"
console.log("pagination.current:", (pagination as any).current); // undefined
console.log("pagination.cursor:", (pagination as any).cursor); // undefined
console.log("Full pagination object:", JSON.stringify(pagination));
// Just shows: {"currentPage":1,"pageSize":25,"mode":"server"}
Attempt 3: Looking at Network Requests
The network tab shows my API being called with:
GET /api/whatsapp/messages?_skip=0&_take=25
GET /api/whatsapp/messages?_skip=25&_take=25 // When scrolling
GET /api/whatsapp/messages?_skip=50&_take=25 // Still no cursor!
It's using traditional pagination even though I'm returning a cursor!
Attempt 4: Different Return Formats
I've tried returning the cursor in different ways from getNextPageParam:
// Tried as string
return JSON.stringify(lastPage.cursor.next);
// Tried as object
return lastPage.cursor.next;
// Tried encoding
return encodeURIComponent(JSON.stringify(lastPage.cursor.next));
// Tried as a simple string ID
return lastPage.cursor.next.id;
None of them work! The data provider still receives currentPage: 1, 2, 3...
My Current Setup
Frontend:
- Refine version: Latest (installed last week)
- React: 18.2.0
- Using Ant Design
Backend:
- NestJS with Prisma
- Returns proper cursor structure:
{
data: [...messages],
total: 1000,
cursor: {
next: { id: "msg_123", timestamp: 1234567890 },
prev: null
}
}
Questions
1. Has anyone actually gotten cursor pagination working with useInfiniteList? I'm starting
to think it might be broken in the current version.
2. Is there a specific format or property name I should use? Maybe Refine expects the cursor
in a different structure?
3. Should I just give up and implement my own infinite scroll? I love Refine, but I'm
burning too much time on this.
4. Is there a way to bypass Refine's data provider for just this one case? Maybe use React
Query directly?
What I Need
If you've successfully implemented cursor pagination with useInfiniteList, PLEASE share:
- Your exact Refine version
- How you return the cursor from getNextPageParam
- How your data provider receives and processes it
- Any workarounds or hacks you had to use
I'm desperate here. I've read every piece of documentation, searched through GitHub issues,
and even tried reading Refine's source code (got lost pretty quickly).
Any help would be massively appreciated. Even if you just have a working example I could
look at, that would be amazing.
Thanks in advance! 🙏
----------------------
You're running into a common pain point with cursor-based pagination and Refine's useInfiniteList: the cursor value returned by getNextPageParam is not automatically passed to your dataProvider's getList as a cursor parameter. Instead, useInfiniteList only updates the pagination.current value (the "page" number), not a custom cursor object. This is why your dataProvider only sees { current: 1, pageSize: 25, mode: "server" } and not your custom cursor.
Why This Happens
Refine's useInfiniteList is designed to work generically with many APIs, so by default, it only passes standard pagination parameters (current, pageSize, mode) to your dataProvider. The cursor you return from getNextPageParam is used internally by TanStack Query to manage pagination state, but Refine does not automatically inject it into the pagination or meta parameters sent to your dataProvider.
How to Fix It
You need to "bridge" the cursor value from getNextPageParam into your dataProvider call. The recommended way is to use the meta property of useInfiniteList to pass the cursor value, and then read it in your dataProvider.
Here's how you can do it:
1. Store the cursor in a React state
2. Read the cursor from meta in your dataProvider
Why This Works
- The meta property is designed to pass custom data from your hook to your dataProvider, including things like headers, custom query params, or, in this case, a cursor value. This is documented in the Refine docs:
You must manually pass the cursor to your dataProvider using the meta property of useInfiniteList. Refine does not do this automatically. This should resolve your issue! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
See meta usage in useInfiniteList - Refine does not automatically pass the cursor from getNextPageParam to your dataProvider; you must do this manually using meta. Additional Notes - If you want to avoid using React state, you could also use a custom hook or context to manage the cursor, but the above approach is the most direct. - Make sure your dataProvider and backend API are both expecting and handling the cursor parameter correctly. References - How to use cursor-based pagination? (Refine Docs) - meta property in useInfiniteList --- Summary:meta
is a special property that can be used to pass additional information to data provider methods for the following purposes: Customizing the data provider methods for specific use cases.
You must manually pass the cursor to your dataProvider using the meta property of useInfiniteList. Refine does not do this automatically. This should resolve your issue! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
<@434784410907443210> Kapa.ai is still learning and improving, please let me know how I did by reacting below.