T
TanStack9mo ago
wise-white

`fetchNextPage` - how does it work?

So does fetchNextPage unpack the result of the queryFn with the new page parameters and the pop it into the pages array? Or does it replace the data.pages entirely? I doubt it's the latter, right? But what it's doing underneath seems really weird and I don't understand it.
14 Replies
wise-white
wise-whiteOP9mo ago
But if it's just adding to the data.pages array, how am I going to know what page I'm on considering useInfiniteQuery doesn't seem to return what page I'm on? Should I be externally keeping track of the page I'm on too? Moreover, if I want to start on, say, page 15, is it possible to have:
let currentPage = 15
// ...
const pagesArray = [];
pagesArray[currentPage] = theData
query.setQueryData(["myEntities"], { pageParam: {...}, pages: pagesArray })
let currentPage = 15
// ...
const pagesArray = [];
pagesArray[currentPage] = theData
query.setQueryData(["myEntities"], { pageParam: {...}, pages: pagesArray })
? (the point of this is that I may not want to start at page 0 ...) Or is this undefined behaviour as far as Tanstack Query's useInfiniteQuery is concerned? So to help, I've got some debugging stuff:
queryFn: async ({ pageParam }) => {
console.log("we're being asked to fetch:", pageParam)
setPage(pageParam.page);
const dat = await (await fetch(`/api/dashboard/class?page=${pageParam.page}&pageSize=${pageParam.pageSize}`)).json();
console.log("dat:", dat);
return dat
},
initialPageParam: { page, pageSize} as any,

getNextPageParam: (lastPage, allPages) => { if(page < totalAvailableCount!.count / pageSize) { return { page: page + 1, pageSize }; } },
getPreviousPageParam: (firstPage, allPages) => { if(page > 0) { return { page: page - 1, pageSize } }; }
queryFn: async ({ pageParam }) => {
console.log("we're being asked to fetch:", pageParam)
setPage(pageParam.page);
const dat = await (await fetch(`/api/dashboard/class?page=${pageParam.page}&pageSize=${pageParam.pageSize}`)).json();
console.log("dat:", dat);
return dat
},
initialPageParam: { page, pageSize} as any,

getNextPageParam: (lastPage, allPages) => { if(page < totalAvailableCount!.count / pageSize) { return { page: page + 1, pageSize }; } },
getPreviousPageParam: (firstPage, allPages) => { if(page > 0) { return { page: page - 1, pageSize } }; }
All within the params of the useInfiniteQuery. I'm really struggling as this seems to not be updating the pages array? How am I supposed to keep track of the page I'm currently on? Sorry but I think I've really screwed up my usage of this framework : - (
foreign-sapphire
foreign-sapphire9mo ago
With an infinite query, it shouldn't matter what page you're on as it's infinite and you're always getting back all pages. If you want to only render one page look for paginated queries in the docs starting on page 15: set initialPageParam Yes, it always adds to the pages
wise-white
wise-whiteOP9mo ago
It's not adding to my array 😦 do you have any guesses as to why?
foreign-sapphire
foreign-sapphire9mo ago
Maybe you're not returning anything from the queryFn ?
wise-white
wise-whiteOP9mo ago
No description
wise-white
wise-whiteOP9mo ago
so I do console log it and i am 99.999999595959595% sure that i do indeed return it and it stays the same, data.pages stays the same BUT i pre-populate data.pages to look like: [empty x 3, Array(25)] if I go to the url /timetable/classes?page=3 (i do index 0, i know its a sin for pagination) thanks for your help btw i know i'm really breaking tanstack query here and i'm an idiot but i have very specific requirements ;-; i mean i suspect this is the issue but how could that possibly be causing my issue?! I'm so confused.
foreign-sapphire
foreign-sapphire9mo ago
I would need to see a minimal reproduction
wise-white
wise-whiteOP9mo ago
OK no worries, I'll work on that hopefully this weekend 👍 thanks If i solve it while doing the reproduction ill post it in here too 👍 As far as reproduction, I think this may be the best I can do:
const {
data,
error,
fetchNextPage,
fetchPreviousPage,
hasNextPage,
isFetching,
hasPreviousPage,
} = useInfiniteQuery({
queryKey: ["classes"],
queryFn: async ({ pageParam }) => {
console.log("we're being asked to fetch:", pageParam)
setPage(pageParam.page);
const dat = await (await fetch(`/api/dashboard/class?page=${pageParam.page}&pageSize=${pageParam.pageSize}`)).json();
console.log("dat:", dat);
return dat;
},
initialPageParam: { page, pageSize} as any,

getNextPageParam: (lastPage, allPages) => { if(page < totalAvailableCount!.count / pageSize) { return { page: page + 1, pageSize }; } },
getPreviousPageParam: (firstPage, allPages) => { if(page > 0) { return { page: page - 1, pageSize } }; }
})
const {
data,
error,
fetchNextPage,
fetchPreviousPage,
hasNextPage,
isFetching,
hasPreviousPage,
} = useInfiniteQuery({
queryKey: ["classes"],
queryFn: async ({ pageParam }) => {
console.log("we're being asked to fetch:", pageParam)
setPage(pageParam.page);
const dat = await (await fetch(`/api/dashboard/class?page=${pageParam.page}&pageSize=${pageParam.pageSize}`)).json();
console.log("dat:", dat);
return dat;
},
initialPageParam: { page, pageSize} as any,

getNextPageParam: (lastPage, allPages) => { if(page < totalAvailableCount!.count / pageSize) { return { page: page + 1, pageSize }; } },
getPreviousPageParam: (firstPage, allPages) => { if(page > 0) { return { page: page - 1, pageSize } }; }
})
^ This is the query. It is initially populated as such:
const entrantData = await GetClassesOnServer({
page, pageSize, additionalFilter
})

const pagesObj = [];

pagesObj[page] = (entrantData as any)[0]!.classesData;

queryClient.setQueryData(["classes"], {
pages: pagesObj,
pageParams: { page, pageSize } // I set this as an object but I don't think it's supposed to be one?
});
const entrantData = await GetClassesOnServer({
page, pageSize, additionalFilter
})

const pagesObj = [];

pagesObj[page] = (entrantData as any)[0]!.classesData;

queryClient.setQueryData(["classes"], {
pages: pagesObj,
pageParams: { page, pageSize } // I set this as an object but I don't think it's supposed to be one?
});
An onclick on a next button does: fetchNextPage(); That's simply it.
wise-white
wise-whiteOP9mo ago
This is data.pages before clicking the button:
No description
wise-white
wise-whiteOP9mo ago
This is that console.log(dat) - it's definitely the next page, and it's what gets returned in queryFn:
No description
wise-white
wise-whiteOP9mo ago
And here's data.pages after:
No description
wise-white
wise-whiteOP9mo ago
The same [array(25)] - the new data is nowhere to be seen.
ambitious-aqua
ambitious-aqua9mo ago
A reproduction means a runnable example using stackblitz or codesandbox, not a bunch of code snippets
wise-white
wise-whiteOP9mo ago
It would be a little hard to get a working DB, prisma, SSR with the querydata set. I would have figured that this is enough to figure out where the issue is. My issue does come down to this thread though: https://discord.com/channels/719702312431386674/1315425016149442673 I do not have any idea what pageParams is supposed to be. Even the docs seem to be confusing in this: const skipToCursor50 = () => fetchNextPage({ pageParam: 50 }) The above gives me a typescript error.
Object literal may only specify known properties, and 'pageParam' does not exist in type 'FetchNextPageOptions'.ts(2353)
(property) pageParam: {
page: number;
pageSize: number;
}
Object literal may only specify known properties, and 'pageParam' does not exist in type 'FetchNextPageOptions'.ts(2353)
(property) pageParam: {
page: number;
pageSize: number;
}
Why is it an array? How would I possibly use this array to keep track of the current page? When I do make the call, ignoring the TS error I get when passing pageParams directly to fetchNextPage it does not seem to use the updated parameter whatsoever. Why does data.pages not populate if pageParams is an object? I mean not actually "why" that happens, I don't need the specific line of code where this procedure fails, I just need to know how pageParams works now.

Did you find this page helpful?