React - Pagination (Part 2)


In this video we will continue on implementing the Pagination component integration with our React CRUD application.

At the end of the last video we had set up our Pagination component and hooked up the front end - clicking on stuff, making sure the UI behaved as expected, that sort of thing.

In this video we are going to sort out the backend integration.

Our Symfony 3 REST API is set up to return response with pagination metadata. To work with the API's pagination implementation, we must manipulate the URL that begins the request.

All we care about at this stage is making sure we pass through the ?page={someNumber} part of the URL. The way we do this in React is different to than in Angular. So here goes!

Extracting fetchBlogPosts()

Currently we call fetchBlogPosts() and handle the response directly inside componentDidMount. This is fine for the initial page load, but we have two choices:

  1. either copy / paste a whole bunch of code
  2. or extract the shared code to a class method (function) and call that instead

Ok, so obviously #2 is a better choice.

In our basic CRUD application the list function simply showed everything, so there only ever the point in handling the initial component mounting phase. Anyway, now we have multiple ways of changing the returned list so we need a better solution.

Let's extract the whole of the fetchBlogPosts() chain to its own method, which we will call getBlogPosts:

// /src/containers/list.js

    getBlogPosts() {
        fetchBlogPosts()
            .then(response => {
                console.log('blog posts', response);
                this.setState({
                    blogPosts: response.items,
                    currentPageNumber: response.currentPage,
                    numItemsPerPage: response.numItemsPerPage,
                    totalItems: response.totalCount
                });
            });
    }

    componentDidMount() {
        this.getBlogPosts();
    }

At this stage our extract is done, and we should still have a working component.

Passing Page Numbers

We need to pass the page number through to the API somehow.

The first step is to get the parameter to the Symfony 3 REST API calling function.

The second step will be to create a URL query string from the passed in parameters.

Handling the first step then involves updating our function & method signatures:

// /src/containers/list.js

    getBlogPosts(pageNumber) {
        fetchBlogPosts(pageNumber)
            .then(response => {
                console.log('blog posts', response);
                this.setState({
                    blogPosts: response.items,
                    currentPageNumber: response.currentPage,
                    numItemsPerPage: response.numItemsPerPage,
                    totalItems: response.totalCount
                });
            });
    }

    componentDidMount() {
        this.getBlogPosts(1);
    }

And on the Api.js file we need to do that second piece of work:

// /src/actions/blogPostActions.js

export function fetchBlogPosts(pageNumber) {
    let p = new URLSearchParams();
    p.append('page', pageNumber || 1);

    console.log('http://api.symfony-3.dev/app_dev.php/posts?', 'http://api.symfony-3.dev/app_dev.php/posts?' + p);

    return fetch('http://api.symfony-3.dev/app_dev.php/posts?' + p, {
        method: 'GET',
        mode: 'CORS'
      })
      .then(res => res.json())
      .catch(err => err);
}

If you have never seen or used URLSearchParams before, it is really nice. You can learn more about it here and here.

What we do here is grab a new instance of URLSearchParams, and add a key / value pair (page / pageNumber, or 1 as a default) to the eventual output.

To make this work we need to update our URL slight, adding the trailing ?, then combining our hardcoded Symfony 3 API URL with the outcome of p.toString() - which is called implicitly when we combine the API URL and this p object.

Ok, now we are getting somewhere.

This modifies our URL to something like:

http://api.symfony-3.dev/app_dev.php/posts?page=1

or

http://api.symfony-3.dev/app_dev.php/posts?page=4

or whatever other number the we pass in. Nice.

We already did all the hard work in the previous video to ensure that this all worked when we hooked up the back end.

You may have already experienced a feeling like this if you have ever done TDD. When you go ahead and combine two components that have only worked together in a test suite, and they suddenly fit together - as if by magic. The magic being the hard work and effort you put in up front :)

Ok, this wraps up Pagination inside our React CRUD app. In the next video we will cover Sorting.

Code For This Video

Get the code for this video.

Episodes