When working with data, sometimes you'll find yourself needing to deal with pagination. Usually this can be quite the cumbersome task, but not with react-query
! It provides you with a hook named usePaginatedQuery
where we can use things like resolvedData
that will either resolve to the latest page's data or if fetching a new page, the last successful page's data. We will send a paginated query with Graphql and wire it up to buttons that allow us to switch back and forth between paged data.
Domitrius Clark: [0:00] Now let's deal with pagination using our usePaginatedQuery hook from the react-query against our GraphQL endpoint. First, we'll define some state that'll keep track of which page we're on. We'll give it an initial value of one.
[0:20] We'll define a constant to hold onto our query definition, called getCharacters. Then inside of our template literal, we'll define a query called paginatedCharacters. We're going to give it an argument of page, which is equal to an integer.
[0:35] We'll define characters, where we can set page to our page variable from above. Then we'll define results, where we want to get back our ID, our image, and the name of the character.
[0:55] We've defined our getCharacters query. Let's go down and invoke our usePaginatedQuery and de-structure a few things. We're going to want the status, our resolved data, the error, and isFetching for our usePaginatedQuery.
[1:11] The reason we're using resolved data over regular data is that resolved data gives us the last known successful query result. As new page queries resolve, resolved data remains available to show the last page's data while a new page is requested. When the new page data is received, resolved data gets updated to the new page's data.
[1:33] Now we can define our query key as an array with characters as the key and page as a variable that we want sent to our fetch function. We can start defining our fetch function with a call to async, pass in the key in the page, define a characters constant, and await our request to the GraphQL endpoint.
[1:58] The request will take in three arguments -- the first being the GraphQL endpoint, the second being our query constant from above, of getCharacters, and the third being our page that we'll be sending to our query.
[2:15] All that's left to do is return the characters. Now that we've saved, you'll see our editor is yelling at us for some unused variables. Let's go down and clean up the JSX and start adding the elements that are going to use those variables.
[2:33] First, let's use our status variable and check to make sure if status is equal to loading, that we return a p tag with loading. Next, we can check status again to make sure that it's not equal to error. If it is equal to error, we can return a p tag, use the error variable from above, and check the error.message.
[3:00] We'll come down inside of our return. We'll put our curly brackets around our resolvedData.characters.results.map.
[3:10] We'll take the character. We'll return a div. On our div, we'll put a key of the character.id.
[3:23] Inside of our div, we'll have a p tag for the character.name. Then under our p tag will be an image tag with the source set to the character.image and our alt text set to the character's name. Below that, lets add a span so we can keep track of the current page that we're on.
[4:12] Now we can work on the buttons that will help us control going back and forth between pages. Our first button will be our previous page button. Then we'll copy and paste that and add our next button.
[4:33] Now we can work an onClick into our previous page button. That'll be an anonymous function set to return our setPage function, where we'll call another anonymous function with a previous state argument.
[4:47] We'll set it to Math.max, which allows us to return the largest of zero or more numbers. We'll feed it the previous state minus one and zero so that we get an accurate page count.
[4:59] After that, we can add a disabled attribute. We'll set page equal to one to make sure that if the page is one, we'll disable this button.
[5:09] We can work that onClick into our next page button. That'll be very similar to our setup above, except this time we'll just call previous state plus one inside of our setPage function.
[5:24] When we hit Next Page, we get a new list of characters. We can hit it again. It'll load another page. Now, if we go back, you can see we're cached, and we're disabled again.
[5:35] Last thing we can do is use that isFetching variable from earlier. If it is fetching, we'll return a span of "Loading...". Otherwise, we'll return null.
[5:50] Since the last page's data potentially sticks around between page requests, we can use isFetching to show a background loading indicator since our status of loading won't be triggered during that load. Now the user knows that it's loading when we're hitting Next and Previous Page.