react-paginate: Implementing pagination in React

Submitted by urvashi on Fri, 06/08/2018 - 17:08

For the past two weeks, I have been working with my mentors to implement pagination on the Uploads tab to make the process a bit quicker. Also, I reached out to the users who organize media campaigns on the Programs & Events Dashboard asking for their feedback on the current features and possible improvements they would like to see. 

react-paginate

It is a ReactJS component to render a pagination. 

Pagination implemented on the dashboard

Installation:

$ npm install react-paginate --save

For CommonJS users:

import ReactPaginate from 'react-paginate';

 

Set initial states:

perPage is the number of data items you want on a single page. data array holds all the items. currentPage is the current page selected, initially you may want to set it to 0 i.e. the first page.elements stores the items to be displayed on the current page and offset helps us select those items.

constructor(props) {
    super(props);
    this.state = {
      offset: 0,
      data: [],
      elements: [],
      perPage: 10,
      currentPage: 0,
    };
}

 

Fetch data:

receiveData() {
    $.ajax({
      url      : 'https://ihsavru.me/Demo/uploads.json',
      dataType : 'json',
      type     : 'GET',
       crossDomain: true,

      success: data => {
          this.setState({
            data: data.course.uploads,
            pageCount: Math.ceil(data.course.uploads.length / this.state.perPage)
          }, () => this.setElementsForCurrentPage());
      },

      error: (xhr, status, err) => {
        console.error(this.props.url, status, err.toString());
      }
    });
}
componentDidMount() {
    this.receiveData();
}

Here, we set the data and pageCount after fetching it from the url. You might want to keep in mind that Math.ceil() returns the smallest integer greater than or equal to a given number, if we don't ceil it then we might run into an issue where the Next button is not disabled even when we are at the last page.  this.setElementsForCurrentPage() is called as a callback.

setElementsForCurrentPage() {
    let elements = this.state.data
                  .slice(this.state.offset, this.state.offset + this.state.perPage)
                  .map(post =>
      ( <img src="{post.thumburl}" />)
    );
    this.setState({ elements: elements });
  }

 

Render first page:


render() {
    let paginationElement;
    if (this.state.pageCount > 1) {
      paginationElement = (
        <ReactPaginate
          previousLabel={"← Previous"}
          nextLabel={"Next →"}
          breakLabel={<span className="gap">...</span>}
          pageCount={this.state.pageCount}
          onPageChange={this.handlePageClick}
          forcePage={this.state.currentPage}
          containerClassName={"pagination"}
          previousLinkClassName={"previous_page"}
          nextLinkClassName={"next_page"}
          disabledClassName={"disabled"}
          activeClassName={"active"}
        />
      );
    }
    return (
      <div className="App">
        {paginationElement}
        {this.state.elements}
        {paginationElement}
      </div>
    );
}

The if statement initializes and renders the paginationElement only if the pageCount is greater than 1 i.e. there are more than 1 page. You can refer to this to see the different types of props passed to ReactPaginate.Since we are rendering two pagination elements, one on the top of the list and one on the bottom, for easier navigation and scrolling, we pass the currentPage selected by clicking on either the top bar or bottom bar to the forcePage props so that both the elements are synchronised.

When a new page is clicked, an event handler function is called which sets the currentPage and the offset and calls the function to set the elements for the selected page. 


handlePageClick(data) {
    const selectedPage = data.selected;
    const offset = selectedPage * this.state.perPage;
    this.setState({ currentPage: selectedPage, offset: offset }, () => {
      this.setElementsForCurrentPage();
    });
  }

 

Styling the pagination element:

The props previousLinkClassName,nextLinkClassName,disabledClassName and activeClassName adds classes to the pagination links in different states which can be used to style your element using CSS.

 

Final Thoughts

This solution may have made the process faster than earlier but the problem arises when the total number of data items reach a comparatively larger number which might result in delayed generation of the uploads.json file by JBuilder on the dashboard. It increases the time taken to fetch the json file even if the image requests on a page is restricted.In the upcoming weeks, I will be working on this and a switchable gallery view and tabular view. 

 

Add new comment

Tags