Pagination and Cache Updates

In this section of the tutorial we’ll cover pagination. You’ll implement a simple pagination approach so that users are able to view the links in smaller chunks rather than all at once with a long list of Link elements.

You also haven’t implemented any cache updates yet, which we’ll also cover. With cache updates you can update the cache when a new post is created, which will cause your app to automatically render the new data.

Preparing the React Components

Like in every other section, let’s first prepare the React components for the new pagination feature. In fact, we’ll just slightly adjust the current routing setup. We’ll reuse the existing LinkList component for two slightly different use-cases and routes.

The first one is to display the 10 top voted links. The second one is to display new links in a list separated into multiple pages that the user can navigate through.

You’ve set up a redirect that sends the user from the homepage to the /new/1 route, which will show any newly added routes. Furthermore the LinkList component is now rendered on two routes, /top for the top links, and /new/:page which is the paginated list of new links.

Before moving on, quickly add a new navigation item to the Header component that brings the user to the /top route.

Next, you’ll update the LinkList component to actually account for the two different responsibilities it now has.

The query now accepts arguments that you’ll use to implement pagination and ordering. The file is also now exporting FEED_QUERY because you’ll be needing it in a later step to implement some cache updates.

  • skip defines the offset where the query will start. If you for instance passed a value of 10 for this argument, it means that the first 10 items of the list will not be included in the response.
  • first then defines the limit, or how many elements, you want to load from that list. Say, you’re passing the 10 for skip and 5 for first, you’ll receive items 10 to 15 from the list.
  • orderBy defines how the returned list should be sorted.

To actually pass the variables into the useQuery hook’s variables argument you’ll now create a small memo hook that returns the variables object.

Here, you’re checking what page the user is on by looking at some props that react-router passes to the LinkList component. The location prop tells you more about the current route. In this case you’re checking the pathname for new, which indicates that the user is on the /new/:page route. Then you’re also parsing the current page from react-router’s match.params prop.

The variables are now also including the 'createdAt_DESC' mode for the /new route to make sure that the newest links are displayed first. The ordering for the /top route will be calculated manually based on the number of votes on each link, which you’ll be implementing in just a bit.

Lastly, let’s update the Link component’s index prop so that the numbers change correctly when the page is switched, for instance to /new/2.

Now you can manually navigate to /new/1, /new/2, and so on, provided you’ve created enough links on your GraphQL API. The index number of the links will correctly change per page!

Implementing navigation

Next, let’s add some buttons for the user to switch between pages.

Lastly you’ll need to ensure that when the /top route is opened, the list of links is sorted by the number of links. You’ll only need to replace the linksToRender variable with some more logic to make this work.

Here, for the /new route the memo hook is returning the links from the query without changes, as before. That’s because the orderBy argument on the query already asks for ordered data for this route. The server doesn’t support sorting by votes however, so on the /top route the links are manually sorted by how many votes they have.

What are urql’s request policies about?

Back when you’ve created the CreateLink page, you saw how the UI doesn’t give any feedback when creating a new link, apart from redirecting to the homepage. Any links that are created in the app aren’t immediately shown on the /new/1 route.

This is because a normalized cache cannot relate the newly created link that your GraphQL API sends back with the queries in LinkList. Instead it only shows the stale, outdated data it knows about.

One simple way to fix this is to pass a different “request policy” to useQuery. We can use different policies to tell urql how to treat cached data. By default, it will always be using cache-first, which means that if a query exists in the cache, urql won’t make another network request.

There are several request policies that tell the cacheExchange in your urql Client how to treat cached data:

  • cache-first prevents a network request, when the query’s result has already been cached.
  • cache-only prevents a network request, even when the query’s result has never been cached.
  • network-only always sends a network request to get a query’s result and ignores the cache.
  • cache-and-network returns a query’s cached result but then also makes a network request.

As you can see, you could use the last request policy, cache-and-network, to update the /new/1 page automatically from your GraphQL API, when you’re redirected to it from /create, like so:

const [result] = useQuery({
  query: FEED_QUERY,
  requestPolicy: 'cache-and-network'

However, this is not what we’ll be doing to solve this problem in this tutorial.

Cache Updates when creating links

With @urql/exchange-graphcache there’s an easy fix to update the cache after a mutation completes. You can pass an updater to the Graphcache exchange that tells it how to update the normalized cache data manually!

This is all it takes to update some cache data after a mutation is performed! ✨

This has the added advantage that you’ll only be using the data that comes back from the mutation. With this approach you’ll never make additional network requests, when the normalized cache already has enough information, which is great!

You can add any number of update functions to the updates config. In this example, we’ve only added a handler for the post mutation. The function receives the data of the mutation, any arguments that have been passed to the mutation field, and an instance of the cache. The cache itself has a method called updateQuery that can be used to update the data for a given query in the cache.

Go ahead and test this by running yarn start in a terminal and navigating to http://localhost:3000/create. Then submit a new link and verify that your newly created link shows up on the /new/1 page.

Unlock the next chapter
How do you configure mutation updates with '@urql/exchange-graphcache'?
You pass an 'update' argument to the 'useMutation' hook
You set up a new 'useUpdate' hook with the new data
You call 'updateQuery' on the cache instance with the new data
You pass an 'updates' config with an updater function that uses 'updateQuery' to the cache exchange