GraphQL pagination in Nuxt 3

Hello, I need help with pagination for my blog.

Iā€™m using Nuxt 3/vue 3 and the useGraphqlQuery.ts composable and refresh() after clicking a ā€˜load moreā€™ button. The refresh seems to work (I displayed ā€˜pendingā€™ and see it change), but my data does not update.

When searching for the how-to, I ran into a few comments saying it has to do with useFetch, that it runs only on the initial page load and after that everything happens client side. But that would mean I have to load all records at once, which slows down my website.
So how can I use the ā€˜firstā€™ and ā€˜skipā€™ parameters in GraphQL to load only a certain amount of records at a time and load an additional set of records (serverside) everytime the ā€˜load moreā€™ button gets clicked?

Does anyone have an example of how to achieve this?

As far as I can see the demo Nuxt blog doesnā€™t have pagination implementedā€¦

Thanks in advance!

Hi @chantalsloep,

Welcome to the community!

I think this might be more of a Vue.js question suitable for a Vue forum, rather than a DatoCMS question specifically? Sorry, weā€™re not experts in Vue/Nuxt, we just provide some basic examples to get you startedā€¦

That said, though, Iā€™ll try to see if I can offer some places to get startedā€¦ but please double-check this with more knowledgeable Vue.js devs before you go to production :slight_smile: I am not sure if any of the following are considered Vue best practices.

If you donā€™t have that many posts

If this is for your main index page/home page and you only have a few posts (like fewer than 100) and youā€™re only loading a few short fields for each one (like their title and link and a thumbnail), itā€™s probably fine to just fetch them all in one go (i.e. fetching up to 100 posts at a time with those fields). You donā€™t have to show them all on the UI at once, but the data can still be loadedā€¦ the JSON for that isnā€™t very big, since itā€™s just a bunch of easily-compressable text. On the UI side you can do something like the ā€œPush numberā€ example in this example.

If you really do need pagination

If you do have a lot of posts and need real pagination, the above wonā€™t be enough. Youā€™ll need real pagination. On the DatoCMS side, it comes down to two GraphQL parameters: first and skip.

For example:

  • first: 2, skip: 0 will get you posts 1-2
  • first: 2, skip: 2 will get you posts 3-4

Or in the playground:

So thatā€™s how youā€™d fetch the data from our API.

As for clientside fetches on the Vue side, it looks like thereā€™s some prebuilt libs/components that might help: https://vue3-infinite-loading.netlify.app/

Or some tutorials: How to implement infinite scroll with Vue - LogRocket Blog or javascript - Load more button with useFetch (concatenate old and new array) - Stack Overflow

It looks to me like you have to juggle some combination of refs, setters, and maybe watchers inside composables, all async. There are some examples in the above links that will hopefully helpā€¦


Please be aware that doing this will mean that your website visitors will be hitting the DatoCMS API directly, meaning youā€™re getting billed for API calls every time an individual visitor ā€œloads moreā€. If you donā€™t have that many posts, it might be better to just handle it serverside and send them an index of all the posts at once (not the entire post body, which would still be a separate page, just a listing of their titles/thumbnails/etc). For example, a JSON of 500 entries of a format like this:

  {
    "_id": "6618549c6b877b17d7322f4c",
    "about": "Proident adipisicing anim voluptate mollit culpa ut magna occaecat eu reprehenderit anim."
  },
  {
    "_id": "6618549c6235300e902f645b",
    "about": "Sunt enim velit ipsum do cupidatat excepteur."
  },
  {
    "_id": "6618549c7ddfeaf3c13d43e3",
    "about": "Minim adipisicing ad dolore dolore dolore pariatur irure exercitation proident ea do in proident amet."
  },
  {
    "_id": "6618549c99f9c7ab5cdaf315",
    "about": "Consectetur eu esse ea mollit aute consectetur tempor in et ea esse eu sit elit."
  }

starts out as ~55kB but gzips down to 18kB, for example. That may well be smaller than including a lib for clientside pagination, or even if you do it simply with useFetch and composables, repeated round-trip network calls are probably slower than just downloading 18 kB all at once.

Thank you for your reply. I didnā€™t think about the billing for the api calls, thatā€™s a really good point. I will get the maximum 100 posts at once and handle the pagination afterwards.
Thanks a lot also for the links to the examples, just what I needed!

1 Like