A React paginated table is useful when presenting data in an organised and readable format. It’s a way to present information in a manageable and organized manner, especially when dealing with a large amount of data that wouldn’t fit comfortably on a single page.

This tutorial shows you how to create your own paginated table fast and easy in React JS without using DataTables or any other framework for that matter.

Want to use React with DataTables? See this tutorial instead

Benefits of Paginated Tables

Key features of a paginated table include:

  1. Pagination Controls: Paginated tables typically include controls such as page navigation buttons (e.g., “Next Page,” “Previous Page”), page number indicators, and sometimes a dropdown menu to select the number of items displayed per page.
  2. Data Organization: The data is organized into rows and columns, similar to a traditional table. Each row represents a single record or entry, while each column represents a specific attribute or field of the data.
  3. Limited Display: Only a subset of the total dataset is displayed on each page, usually determined by the number of rows visible per page. This helps to prevent information overload and improves the user experience by presenting a manageable amount of data at a time.
  4. Navigation: Users can navigate between pages to view different segments of the dataset. Pagination controls allow users to move forward or backward through the pages, jump to a specific page, or adjust the number of items displayed per page.
  5. Efficient Loading: Paginated tables often incorporate techniques to efficiently load data, such as lazy loading, where additional pages of data are fetched from the server as needed, or server-side pagination, where only the relevant subset of data is retrieved from the server for each page.

Let’s see how to create a paginated table from an API data.

1. Get Data From The API

constructor(props){
     super(props);
     this.state = {
       data: [],
       postsPerPage: 10,
       currentPage: 1
     }
   } 

getPosts = async () => {
     const url = "https://jsonplaceholder.typicode.com/todos/";
     const obj = {
       method: "GET",
       headers: {
         Accept: "application/json",
         "Content-Type": "application/json"
       }
     }

     await fetch(`${url}`, obj)
     .then((response) => response.json())
     .then((responseJson) => {
       console.warn(responseJson);
       this.setState({ data: responseJson })
     })
     .catch((error) => {
       console.warn(error);
     })
   }

2. Display data from the API on the table

showData = () => {

      const { postsPerPage, currentPage, data } = this.state;
      const indexOfLastPage = currentPage * postsPerPage;
      const indexOfFirstPage = indexOfLastPage - postsPerPage;
      const currentPosts = data.slice(indexOfFirstPage, indexOfLastPage)

     try{
     return currentPosts.map((item, index) => {
       return(
         <tbody>
         <tr>
         <td>{postsPerPage * (currentPage-1)+index+1}</td>
         <td>{item.userId}</td>
         <td>{item.title}</td>
         <td>{item.completed.toString()}</td>
         </tr>
         </tbody>
       )
     })
   }catch(e){
     alert(e.message)
   }
   }

 render() {
     return (
       <div className="container">
       <table className="table align-items-center justify-content-center mb-0">
       <thead>
       <tr>
       <th>S/N</th>
       <th>UserId</th>
       <th>Title</th>
       <th>Completed</th>
       </tr>
       </thead>
       {this.showData()}
       </table>
      </div>
      )
}

3. Add the pagination component

 showPagination = () => {
     const { postsPerPage, data } = this.state;
     const pageNumbers = [];
     const totalPosts = data.length;

     for(let i = 1; i<=Math.ceil(totalPosts/postsPerPage); i++){
       pageNumbers.push(i)
     }

     const pagination = (pageNumbers) => {
       this.setState({currentPage: pageNumbers})
     }

     return(
       <nav>
       <ul className="pagination">
       {pageNumbers.map(number => (
         <li key={number} className={this.state.currentPage === number ? 'page-item active' : 'page-item' }>
         <button onClick={()=> pagination(number)} className="page-link"> {number} </button>
         </li>
       ))}
       </ul>
       </nav>
     )
   }

Here’s the full code for the React paginated table:

import React, { Component } from 'react';
import './App.css';

 class App extends Component {

   constructor(props){
     super(props);
     this.state = {
       data: [],
       postsPerPage: 10,
       currentPage: 1
     }
   }

   getPosts = async () => {
     const url = "https://jsonplaceholder.typicode.com/todos/";
     const obj = {
       method: "GET",
       headers: {
         Accept: "application/json",
         "Content-Type": "application/json"
       }
     }

     await fetch(`${url}`, obj)
     .then((response) => response.json())
     .then((responseJson) => {
       console.warn(responseJson);
       this.setState({ data: responseJson })
     })
     .catch((error) => {
       console.warn(error);
     })
   }



   showData = () => {

      const { postsPerPage, currentPage, data } = this.state;
      const indexOfLastPage = currentPage * postsPerPage;
      const indexOfFirstPage = indexOfLastPage - postsPerPage;
      const currentPosts = data.slice(indexOfFirstPage, indexOfLastPage)

     try{
     return currentPosts.map((item, index) => {
       return(
         <tbody>
         <tr>
         <td>{postsPerPage * (currentPage-1)+index+1}</td>
         <td>{item.userId}</td>
         <td>{item.title}</td>
         <td>{item.completed.toString()}</td>
         </tr>
         </tbody>
       )
     })
   }catch(e){
     alert(e.message)
   }
   }

   showPagination = () => {
     const { postsPerPage, data } = this.state;
     const pageNumbers = [];
     const totalPosts = data.length;

     for(let i = 1; i<=Math.ceil(totalPosts/postsPerPage); i++){
       pageNumbers.push(i)
     }

     const pagination = (pageNumbers) => {
       this.setState({currentPage: pageNumbers})
     }

     return(
       <nav>
       <ul className="pagination">
       {pageNumbers.map(number => (
         <li key={number} className={this.state.currentPage === number ? 'page-item active' : 'page-item' }>
         <button onClick={()=> pagination(number)} className="page-link"> {number} </button>
         </li>
       ))}
       </ul>
       </nav>
     )


   }

   componentDidMount(){
     this.getPosts()
   }

   render() {
     return (
       <div className="container">
       <table className="table align-items-center justify-content-center mb-0">
       <thead>
       <tr>
       <th>S/N</th>
       <th>UserId</th>
       <th>Title</th>
       <th>Completed</th>
       </tr>
       </thead>
       {this.showData()}
       </table>

       <div style={{ float: 'right' }}>
       {this.showPagination()}
       </div>

       </div>
     );
   }
 }

export default App;

Result of the React paginated table

Have anything to add? Let me know in the comments.

View Comments

  • Nice tutorial,can you please explain how I can add a search bar to this kind of pagination table that only searches data through ID alone.

Share
Published by
codeflare

Recent Posts

Build a Node JS Web Server

A web server is the software responsible for receiving requests from clients, processing those requests,…

1 day ago

Shell Prompt Tutorial

A shell prompt is the text displayed by a command-line shell to show that it is ready…

5 days ago

The SOC Analyst

A SOC Analyst (Security Operations Center Analyst) is one of the frontline defenders of an organization’s cybersecurity…

3 weeks ago

Building an Offline-Friendly Image Upload System

Most image upload systems assume one thing: the user has a stable internet connection. That assumption…

3 weeks ago

JavaScript Background Sync API

Imagine a user submits a form while their internet connection suddenly disappears. Normally, the request…

3 weeks ago

10 Signs Your PC Has Been Hacked

Cybercriminals don't always announce their presence. Many compromises are designed to remain unnoticed for weeks…

1 month ago