#Understanding usePaginatedQuery

47 messages · Page 1 of 1 (latest)

rocky cosmos
#

I'm trying to wrap my head around how to use a page based usePaginatedQuery, so basically if a user hits /posts?page=1 or /posts?page=2, I want to fetch 5 items and change the offset.

the usePaginatedQuery seems to be more like a lazy scroll type of thing. Maybe I'm missing something?

wary hingeBOT
#

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!

stray canopy
#

yes usePaginatedQuery isn't really conducive to offset-based pagination. the problem is you have to know where in the table to start, and we can't just tell the database "skip over 500 documents, then give a page of size 50"

#

if you want the pages to be defined by a field, like each page is a day's worth of documents, you can query and filter against the by_creation_time index

#

if you actually want offset-based pagination, you can use the Aggregate component

#

because one you have aggregates, it's feasilbe to say "skip over 500 documents"

harsh shoal
#

i faced same thing a little while ago so i came up with this

https://github.com/hamzasaleem2/convex-tanstack-table/blob/main/src/useSimplePaginatedQuery.ts

its just a wrap over useQuery but did the job for me for offsets

it gives you this hook to use:

  status,
  currentResults,
  loadNext,
  loadPrev,
  currentPageNum,
  setPageSize,
  pageSize
} = useSimplePaginatedQuery(myQuery, initialArgs, { initialNumItems: 10 });```

tanstack table demo: https://convex-tanstack-table.vercel.app/
i didn't worked out alot of things in this which can be better. but you are welcome to try and happy to take a feedback on this too.
GitHub

Contribute to hamzasaleem2/convex-tanstack-table development by creating an account on GitHub.

rocky cosmos
#

@harsh shoal would the query on the convex query just need to return a pagination object?

stray canopy
#

^ that helper looks great and is the pattern i would recommend if you're okay with calling loadNext until you get to the page you want

rocky cosmos
#

easiest approach I can think is just add an auto incrementing id to the records

#

and then calculate the page / offset using that with a .take max page length?

stray canopy
#

if auto incrementing id is feasible (no deletes, ordering by creation time) that ^ is equivalent to and better than going all-in on aggregates

rocky cosmos
#

yeah I just want a list of blog posts by date

#

order desc

#

going to add this

export const addAutoIncrementingIdToPosts = internalMutation({
args: {},
async handler(ctx) {
const posts = await ctx.db.query("blogPosts").order("desc").collect();
await Promise.all(
posts.map((post, index) =>
ctx.db.patch(post._id, { incrementingId: index + 1 })
)
);
},
});

#

run it, then just do a take(PAGE_SIZE)

stray canopy
#

how will you calculate the index for new blog posts? (i'm asking because this looks like it won't work, unless the set of blog posts is fixed or you recalculate the incrementingId field whenever a new one is added)

#

i.e. looks like this will generate incrementingId: 1 for the most recent blog post, incrementingId: 2 for the next, etc. so if you want to add a new blog post and keep the ordering, it would need to have incrementingId: 0

rocky cosmos
#

sorry I've modified since posting

#
const PAGE_SIZE = 5;

export const getPosts = query({
  args: {
    page: v.number(),
  },
  handler: async (ctx, args) => {
    const startId = (args.page - 1) * PAGE_SIZE + 1;

    const page = await ctx.db
      .query("blogPosts")
      .withIndex("incrementingId_index", (q) =>
        q.gte("incrementingId", startId)
      )
      .take(PAGE_SIZE);

    return page;
  },
});
#

I could also probably just do order('desc') so that id 1 is the oldest I think

#

or just don't use ids and instead use proper dates

stray canopy
#

you're right; looks like it does work. carry on 🙂

silk iris
harsh shoal
silk iris
thorny gale
#

It sounds like either your table is remounting, an intermediate container within your table housing the rows is remounting, or an intermediate empty state is occurring, which wouldn't be from the query itself. How to troubleshoot depends on your implementation, but I would first look at how you're handling the loading state, if at all.

silk iris
thorny gale
#

Just looked at some reference implementations - this is normally how page based pagination works. Eg., google results, github issues - the whole page reloads and scrolls to top. I'm not saying what you're trying to do isn't possible, just pointing this out in case it makes this issue less of a blocker for you.

thorny gale
#

Rendering is branched on loading state, it'll scroll up every time there's a loading event because the rendered table disappears. You'd have to continuously show the old data until the new data is available to do what you're trying to do.

silk iris
# thorny gale Just looked at some reference implementations - this is normally how page based ...

Thanks for pointing this out, since i jumped to another project I've been trying to iterate on my tables so i need to go back and see. Between the frameworks, the tanstack query code, the tanstack table w/shadcn, and all the native paginated helpers in convex my brain is fried on tables, i thought this was generally expected. I do think this is something everyone suffers through or just lives with in various ways. It's probably low on the list of priorities but high on the list of friction if you attempted to analyze what was the perfect table in the convex ecosystem is.

thorny gale
#

That's fair. Also tables are just hard in general. TanStack's tooling is the best I've seen, but... they're still tables, and they're still kinda hard.

silk iris
# thorny gale That's fair. Also tables are just hard in general. TanStack's tooling is the bes...

I'm very lost, so i made a repoduction, i could hack this all the way to working but i only know the dirty hacky way, and i'd be left wondering the right way.

I left it with many state issues
To me these are minimal table features, Debounced Search using convex search Index, A filter field, a results per page, previous and next, and change sort order.
https://github.com/amp127/real-convex-tanstack-table

I'd be happy to tip anyone for taking this across the finish line. Interested @harsh shoal ?

GitHub

Contribute to amp127/real-convex-tanstack-table development by creating an account on GitHub.

silk iris
thorny gale
#

Can’t tell if “just useQuery” is good or bad lol

silk iris
# thorny gale Can’t tell if “just useQuery” is good or bad lol

Exactly, its probably not useful for a table that is refreshing as that was why the team made useStablePaginatedQuery for that temporary undefined state. But i don't see that happening.. (i added a buttons for quick adding) so im a bit more confused. i think ill upload my various iterations of these things to that github

silk iris
thorny gale
#

Nice!!

#

Even the anti flicker one still flickers though

#

so your status is none of these actually fix your problem, is that right?

silk iris
# thorny gale Even the anti flicker one still flickers though

My status is:
I don't know if any of them are working as expected, i'd like help.
The flicker is the least of my concerns right now, but my computer is so fast that it makes it appear as if its not (almost).
Reset to top of the page is the same? but is that just life?
Is tanstack table part of the issue.

Simple Paginated Query: to make it work is hacky as shit, with useEffects or setting other variables to reset state and i would like help
I'll probably switch to RJ's Next/Prev as ai can at least not screw it up.

Am i missing any other ways.
It would be nice to add infinate scroll demos and use some of the newer features for optiomistic updates.

thorny gale
#

Resetting to top is normal for previous page / next page. For the infinite scroll examples, you're explicitly rendering a loading screen every time they press load more, so it unmounts and remounts scrolled to the top. I use regular usePaginatedQuery in production for infinite scroll and it works great, any of these approaches should be fine. Just have to look at the code to troubleshoot specific issues that you're seeing. If you're using AI to write it all the agents may have difficulty getting it right.

#

If you want more help with specific issues, let's start with one problem, and one implementation, and solve it from there. Feels like a bit of a moving target currently.