Shahen 🔺
Shahen 🔺•3mo ago

Paginated query with Tanstack Query

Is there any way to use paginated queries with Tanstack query?
15 Replies
Convex Bot
Convex Bot•3mo ago
Thanks for posting in <#1088161997662724167>. Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets. - Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.) - Use search.convex.dev to search Docs, Stack, and Discord all at once. - Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI. - Avoid tagging staff unless specifically instructed. Thank you!
ballingt
ballingt•3mo ago
@Shahen 🔺 you can use normal Convex paginated queries alongside TanStack ones, that's the thing to do for now if you have ideas for how you'd rather have this work I'd love to hear
Shahen 🔺
Shahen 🔺OP•3mo ago
hey tom, do you have an example of how to implement it?
Shahen 🔺
Shahen 🔺OP•3mo ago
thanks, but I am looking for an example with tanstack query, what would use as the queryFn for example can i use useInfiniteQuery? or do i have to use useQuery(from tanstack) and implement my custom way to display and load more?
ballingt
ballingt•3mo ago
@Shahen 🔺 you can use normal Convex hooks alongside the TanStack Query ones, so instead of useQuery() you'd use the Convex usePaginatedQuery @Shahen 🔺 is there something that you want to behave differently about the Convex usePaginatedQuery?
Shahen 🔺
Shahen 🔺OP•3mo ago
yes for example:
const { data, isPending, error } = useQuery({
...convexQuery(api.functions.myQuery, { id: 123 }),
initialData: [], // use an empty list if no data is available yet
gcTime: 10000, // stay subscribed for 10 seconds after this component unmounts
});
const { data, isPending, error } = useQuery({
...convexQuery(api.functions.myQuery, { id: 123 }),
initialData: [], // use an empty list if no data is available yet
gcTime: 10000, // stay subscribed for 10 seconds after this component unmounts
});
gcTime, is there a way to set that without react query?
ballingt
ballingt•3mo ago
Ah no there is not, it will be 0 for a paginated query
Shahen 🔺
Shahen 🔺OP•3mo ago
my use case, I have 5 big leaderboards on a single page, I want to set some sort of delay so that i can save on resources
ballingt
ballingt•3mo ago
ah gcTime doesn't give you a delay, you'll still be receiving every update gcTime makes the subscription last longer, when the user leaves the page the subscription will remain for e.g. 10 seconds
Shahen 🔺
Shahen 🔺OP•3mo ago
i see
ballingt
ballingt•3mo ago
is that something you'd like? Generally folks using Convex want reactive data, but if you don't want this to be reactive that's reasonable too
Shahen 🔺
Shahen 🔺OP•3mo ago
I love the reactive data for sure, but I'm thinking if i can make these leaderboards more efficient since I don't necessarily need reactive data for it. it could update every 5 minutes and it'd be fine. or maybe I am missing some benefits that convex offers in that kinda case
ballingt
ballingt•3mo ago
Cool, that makes sense. Maybe this could look like
const { data, isPending, error } = useQuery({
...convexNonreactiveQuery(api.functions.myQuery, { id: 123 }),
initialData: [],
});
const { data, isPending, error } = useQuery({
...convexNonreactiveQuery(api.functions.myQuery, { id: 123 }),
initialData: [],
});
Normally Convex queries update live: every time the query result changes (even if that's once a second) a WebSocket message is sent from the server to update the query on the client or convexPollingQuery a simple way to write it today (not tested, something like this) would be
const convex = useConvex();
const { data, isPending, error } = useQuery({
queryFn: ({queryKey}) => convex.query(api.functions.myQuery, queryKey[0]),
queryKey: [{ id: 123 })]
initialData: [],
});
const convex = useConvex();
const { data, isPending, error } = useQuery({
queryFn: ({queryKey}) => convex.query(api.functions.myQuery, queryKey[0]),
queryKey: [{ id: 123 })]
initialData: [],
});
but that's not paginated cool helpful to hear, if you need a paginated query now I'd use the normal reactive one usePaginatedQuery or if you need a nonreactive one, I'd write something that does some manual pagination like this https://github.com/get-convex/convex-demos/blob/main/pagination/src/download.ts so it's not reactive
Shahen 🔺
Shahen 🔺OP•3mo ago
Alright I’ll look into it and get back to you Thanks Tom @ballingt
const convex = useConvex();

const fetchScores = async (pageParam: string | null) => {
const response = await convex.query(api.scorecards.getScorecards, {
tier: tier,
paginationOpts: {
numItems: 5,
cursor: pageParam,
},
});

return response
};

const { data: infinite, fetchNextPage } = useInfiniteQuery({
queryKey: [`scorecard-${tier}`],
queryFn: ({ pageParam }: { pageParam?: string | null }) => fetchScores(pageParam ?? null),
getNextPageParam: (lastPage) => {
return lastPage.isDone ? undefined : lastPage.continueCursor;
},
initialPageParam: null,
// refetchInterval: 10000
})
const convex = useConvex();

const fetchScores = async (pageParam: string | null) => {
const response = await convex.query(api.scorecards.getScorecards, {
tier: tier,
paginationOpts: {
numItems: 5,
cursor: pageParam,
},
});

return response
};

const { data: infinite, fetchNextPage } = useInfiniteQuery({
queryKey: [`scorecard-${tier}`],
queryFn: ({ pageParam }: { pageParam?: string | null }) => fetchScores(pageParam ?? null),
getNextPageParam: (lastPage) => {
return lastPage.isDone ? undefined : lastPage.continueCursor;
},
initialPageParam: null,
// refetchInterval: 10000
})
this is working, and it doesn't seem to be reactive anymore no queries in logs when i update a user score in database when i enable refetchInterval, i do see a new query in logs, i set it to 10 seconds and the query appears in logs every 10 secs only issue is react query cached data is messing with next cursor data

Did you find this page helpful?