Ad

Reusable React Pagination Component

- 1 answer

I am trying to create dynamic pagination react component with reactstrap as UI library. I am stuck around the problem of completing the same.

UsersCard.js

import React, { Component } from 'react'
import axios from 'axios';
import PaginationTable from './PaginationTable';



    export default class UsersCard extends Component {

        constructor(props) {
          super(props)

          this.state = {
              usersData: [],
              loading: false,
              per_page: 3,
              current_page: 1,
              total_data: '',
              currentPosts: []
          }
        }

    async componentDidMount(){
      await axios.get('https://reqres.in/api/users')
        .then(res => {
            this.setState({
              usersData: res.data.data,
              loading: false,
              total_data: res.data.data.length
            })
        })
        .catch(err => console.log(err));

        const indexOfLastPost = this.state.current_page * this.state.per_page;
        const indexOfFirstPage = indexOfLastPost - this.state.per_page;

        const currentPosts = this.state.usersData.slice(indexOfFirstPage, indexOfLastPost);

        this.setState({ currentPosts })

    }

    handleClick = (number) => {
      this.setState({
        current_page: number
      })
    }

      render() {
        const { per_page, handleClick, total_data, current_page, currentPosts } = this.state;

        return (
          <div>
            <table>
                <thead>
                    <tr>
                        <th>Id</th>
                        <th>First Name</th>
                        <th>email</th>
                        <th>Last Name</th>
                    </tr>
                </thead>
                {currentPosts.map(x => {
                return(
                        <React.Fragment key={x.id}>
                                <tbody>
                                    <tr>
                                        <td>{x.id}</td>
                                        <td>{x.first_name}</td>
                                        <td>{x.email}</td>
                                        <td>{x.last_name}</td>
                                    </tr>
                                </tbody>
                        </React.Fragment>
                        )
                })}
            </table>
            <PaginationTable
                      per_page={per_page}
                      current_page={current_page}
                      total_data={total_data}
                      handleClick={handleClick}
                    />
          </div>
        )
      }
    }

PaginationTable.js

import React from 'react';
import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';

const PaginationTable = ({ per_page, total_data, handleClick, current_page }) => {

    let pageNumbers = [];

    for(let i=1; i<= Math.ceil(total_data/per_page); i++)
    {   
        pageNumbers.push(
        <PaginationItem key={i} active={current_page === i ? true : false}>
            <PaginationLink onClick={() => handleClick(i)} target="_blank" rel="nofollow noreferrer" href="#">
                {i}
            </PaginationLink>
        </PaginationItem>)
    }



    return(
            <Pagination aria-label="Page navigation example">
                <PaginationItem disabled={current_page <= 1}>
                    <PaginationLink onClick={()=>handleClick(current_page-1)}
                            previous 
                            target="_blank" rel="nofollow noreferrer" href="#" 
                    />
                    </PaginationItem>

                        {pageNumbers}

                <PaginationItem disabled={current_page >= per_page - 1}>
                    <PaginationLink onClick={()=>handleClick(current_page + 1)}
                            next 
                            target="_blank" rel="nofollow noreferrer" href="#" 
                    />
                </PaginationItem>
            </Pagination>

    )

}

export default PaginationTable;

My problems go like:

1) Reactstrap pagination UI is not showing properly.

2) Whenever I click on the next button, it consoles the error: TypeError: handleClick is not a function.

I am bit new to the dynamic pagination concept and am unable to identify the bug I am stuck with. Kindlt help to resolve the same. Any code improvements are also welcomed.

Ad

Answer

There are multiple problems with this approach:

  1. this.handleClick has to be passed in from the parent.

  2. setState function is asynchronous. So accessing the state right after setting it might not result in the same state you wish. To get around this React gives you a callback function as second argument. This is run only after the state is run.

  3. You are not updating the currentPosts state after change in pagination. Pagination component is only concerned with changing page numbers, the change in data has to manually handled. You can handle this with:

  async componentDidMount() {
    await axios
      .get("https://reqres.in/api/users")
      .then(res => {
        this.setState({
          usersData: res.data.data,
          loading: false,
          total_data: res.data.data.length
        }, () => {
          this.formatData();
        });
      })
      .catch(err => console.log(err));
  }

  formatData() {
    const indexOfLastPost = this.state.current_page * this.state.per_page;
    const indexOfFirstPage = indexOfLastPost - this.state.per_page;

    const currentPosts = this.state.usersData.slice(
      indexOfFirstPage,
      indexOfLastPost
    );

    this.setState({ currentPosts });
  }

  handleClick = number => {
    this.setState({
      current_page: number
    }, () => {
      this.formatData();
    });
  };

Updated Stackblitz

Ad
source: stackoverflow.com
Ad