[Tutorial] Pagination

I’ve written a tutorial on how to add pagination to the blog you create when following the official RW tutorial. Think of it like an optional add-on step to the official tutorial.

The screenshot shows what the tutorial helps you build. (Note the pagination at the bottom.)

It’s heavily inspired by the official example blog code here: https://github.com/redwoodjs/example-blog

When I first started building with Redwood and I wanted to add pagination I found that example, but I didn’t know Apollo and Prisma well enough to be able to use it. I wished there was some tutorial or other explanatory text to go along with the code example.

This is me writing what I wished existed when I first got started

https://tlundberg.com/blog/2020-09-16/redwood-pagination-tutorial/

7 Likes

Thanks so much @Tobbe :rocket:

I vote to make this a Redwood Cookbook article :+1:

All in favor??

4 Likes

I’ve been waiting for this, thank you for writing it up! Look forward to reading it properly :slight_smile:

It’d be an honor. I’ll get a PR up next week

Hmmmmm… what about this? https://github.com/redwoodjs/redwoodjs.com/pull/376

Err. lolwut? That’s a copy/paste of my blog post…

ha! Well, then, should I put you in charge of the Review and Approval?

:rofl:

1 Like

@Tobbe @dthyresson
Just saw this “Pagination helpers” section for Apollo v3. Passing along in case you find it helpful:

I’m not that familiar with Relay, but it looks like Apollo Client has added features to make it “eas[ier] to consume paginated lists from Relay-friendly GraphQL servers”

So, for Redwood Cells, I imagine this could come into play if Redwood’s GraphQL was “relay friendly”.

And after a little reading that mean: https://relay.dev/docs/en/graphql-server-specification.html#preface

  1. A description of how to page through connections.

Which looks like some edges and nodes to make it easy to page through – which I’m assuming is really good for infinite scrolls and the like: next, next, next, next. Rather than say, table lists where you want to go to page 5 of a long list.

uery EndOfRebelShipsQuery {
  rebels {
    name,
    ships(first: 3 after: "YXJyYXljb25uZWN0aW9uOjE=") {
      edges {
        cursor,
        node {
          name
        }
      }
    }
  }
}

which gives you

{
  "rebels": {
    "name": "Alliance to Restore the Republic",
    "ships": {
      "edges": [
        {
          "cursor": "YXJyYXljb25uZWN0aW9uOjI=",
          "node": {
            "name": "A-Wing"
          }
        },
        {
          "cursor": "YXJyYXljb25uZWN0aW9uOjM=",
          "node": {
            "name": "Millenium Falcon"
          }
        },
        {
          "cursor": "YXJyYXljb25uZWN0aW9uOjQ=",
          "node": {
            "name": "Home One"
          }
        }
      ]
    }
  }
}

I guess the cells (or something else) would have to assemble the edges and nodes to present the data. (Maybe the Relay client does this for you? That would be nice.)

This is a good take: https://www.apollographql.com/blog/understanding-pagination-rest-graphql-and-relay-b10f835549e7/

  • paged (ie, limit/offset pagination)
  • infinte scroll
  • cursor-based

So many different ways - depending on what your app needs.

Maybe at some point there is a cookbook for an “infinite scroll” where some identifier denotes the last position and fetch a chunk of data beyond that. You’d need some identifier that was unique and sortable though I believe.

More reading here: https://www.apollographql.com/blog/explaining-graphql-connections-c48b7c3d6976/

The cursor scroll approach works great when you add more and more to the list and you are fetching form the top, then the idea of a page or offset is a moving target:

If the user was on page 1 when the records were added and now navigates to page 2, they will see records 11–15 again! However, a worse scenario is if the user is on page 2 when the records were added and now they navigate to page 1 and will never see records 11–15!

When your core product revolves around a list, like Facebook, it is imperative that you get pagination right. Both scenarios where the user either sees posts twice or the user misses a few posts entirely are unacceptable. Since cursor-based pagination can help avoid this flaw, it makes sense that Facebook always uses cursor-based pagination.

So tldr; what we have in the cookbook is limit/offset pagination :wink: but a cursor/infinite scroll one could be very useful as well – especially when trying to define the cursor identifier. I am not 100% sure that Prisma cuids are sortable, but perhaps they are.

1 Like

I looked at doing cursor-based pagination, but decided to go with regular limit/offset pagination because I wanted the tutorial to be as easy to follow as possible. Sure, there might be some weirdness if three new posts are added to the blog while a user is on a specific page. If the user goes to the next page, the three last posts on the page the user was previously on would appear on the new page they went to as well. But usually posts aren’t added to a blog fast enough for this to be a real problem.

Infinite scroll could be interesting. And that could be added no matter what kind of paging you’re using. But, again, in the interest of keeping the tutorial as easy as possible I skipped this.

1 Like

Haha, found this issue comment regarding the new field policy stuff in Apollo Client 3

Field policies are so confusing that the more I am trying to understand and reading through issues the more I am getting confused!
Can you guys just clear things out on a video or docs. Its really hard to implement pagination with field policies I am finding

- Cache Field Policy: Offset pagination example · Issue #6481 · apollographql/apollo-client · GitHub

100% agree. And for things like paginated tables for “scaffold crud” it suits the use case better.