Working with large datasets in React can be overwhelming. I’ve often faced situations where I needed to display hundreds of records, customer lists, product catalogs, or transaction logs.
Instead of showing everything at once, pagination makes the data manageable. It splits the content into smaller pages and lets users navigate easily.
In this tutorial, I’ll walk you through how I built a React pagination component. I’ll share multiple methods, complete code examples, and practical explanations from my own experience.
Why Pagination Matters
- Performance: Rendering 1,000+ items at once slows down the UI. Pagination solves this.
- User Experience: Users prefer browsing page by page instead of scrolling endlessly.
- Scalability: Works well with APIs that return paginated responses.
Method 1 – Simple Pagination with State
The first method is an easy approach using React’s useState and slice(). This is perfect for small to medium datasets stored locally.
Full Code Example
import React, { useState } from "react";
const data = Array.from({ length: 100 }, (_, i) => `Item ${i + 1}`);
function SimplePagination() {
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 10;
const totalPages = Math.ceil(data.length / itemsPerPage);
const handlePageChange = (page) => {
setCurrentPage(page);
};
const startIndex = (currentPage - 1) * itemsPerPage;
const currentItems = data.slice(startIndex, startIndex + itemsPerPage);
return (
<div>
<h2>Simple Pagination Example</h2>
<ul>
{currentItems.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
<div style={{ marginTop: "20px" }}>
{Array.from({ length: totalPages }, (_, i) => (
<button
key={i}
onClick={() => handlePageChange(i + 1)}
style={{
margin: "0 5px",
padding: "5px 10px",
background: currentPage === i + 1 ? "#007bff" : "#f0f0f0",
color: currentPage === i + 1 ? "#fff" : "#000",
border: "none",
borderRadius: "4px",
cursor: "pointer",
}}
>
{i + 1}
</button>
))}
</div>
</div>
);
}
export default SimplePagination;You can refer to the screenshot below to see the output.

Here, I slice the dataset based on the current page and display only 10 items at a time. The navigation buttons update the currentPage state, which updates the visible items.
Method 2 – Reusable Pagination Component
Once, I had to use pagination across multiple pages in a project. Instead of repeating code, I created a reusable component.
Full Code Example
import React, { useState } from "react";
function Pagination({ totalItems, itemsPerPage, onPageChange }) {
const totalPages = Math.ceil(totalItems / itemsPerPage);
return (
<div style={{ marginTop: "20px" }}>
{Array.from({ length: totalPages }, (_, i) => (
<button
key={i}
onClick={() => onPageChange(i + 1)}
style={{
margin: "0 5px",
padding: "5px 10px",
border: "1px solid #ccc",
cursor: "pointer",
}}
>
{i + 1}
</button>
))}
</div>
);
}
function ReusablePaginationExample() {
const data = Array.from({ length: 50 }, (_, i) => `Customer ${i + 1}`);
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 5;
const startIndex = (currentPage - 1) * itemsPerPage;
const currentItems = data.slice(startIndex, startIndex + itemsPerPage);
return (
<div>
<h2>Reusable Pagination Component Example</h2>
<ul>
{currentItems.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
<Pagination
totalItems={data.length}
itemsPerPage={itemsPerPage}
onPageChange={(page) => setCurrentPage(page)}
/>
</div>
);
}
export default ReusablePaginationExample;You can refer to the screenshot below to see the output.

I created a Pagination component that accepts total items, items per page, and a callback.
This makes it easy to reuse across any dataset without rewriting pagination logic.
Method 3 – Pagination with API Data
Most real-world apps fetch data from an API. In such cases, the backend usually provides paginated results.
Here’s how I handle it in React using fetch and query parameters.
Full Code Example
import React, { useEffect, useState } from "react";
function ApiPagination() {
const [data, setData] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 10;
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/posts?_page=${currentPage}&_limit=${itemsPerPage}`)
.then((res) => res.json())
.then((json) => setData(json));
}, [currentPage]);
return (
<div>
<h2>API Pagination Example</h2>
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
<div style={{ marginTop: "20px" }}>
<button
onClick={() => setCurrentPage((prev) => Math.max(prev - 1, 1))}
disabled={currentPage === 1}
>
Prev
</button>
<span style={{ margin: "0 10px" }}>Page {currentPage}</span>
<button onClick={() => setCurrentPage((prev) => prev + 1)}>Next</button>
</div>
</div>
);
}
export default ApiPagination;You can refer to the screenshot below to see the output.

Here, I fetch posts from a JSON API using _page and _limit parameters. The navigation buttons update the current page, and the API returns the correct slice of data.
Method 4 – Use the react-paginate Library
Sometimes, I prefer not to reinvent the wheel. The react-paginate library provides a ready-to-use pagination component.
Full Code Example
import React, { useEffect, useState } from "react";
import ReactPaginate from "react-paginate";
function LibraryPagination() {
const [data, setData] = useState([]);
const [currentPage, setCurrentPage] = useState(0);
const itemsPerPage = 10;
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/comments`)
.then((res) => res.json())
.then((json) => setData(json));
}, []);
const offset = currentPage * itemsPerPage;
const currentItems = data.slice(offset, offset + itemsPerPage);
const pageCount = Math.ceil(data.length / itemsPerPage);
const handlePageClick = ({ selected }) => {
setCurrentPage(selected);
};
return (
<div>
<h2>React-Paginate Library Example</h2>
<ul>
{currentItems.map((item) => (
<li key={item.id}>{item.email}</li>
))}
</ul>
<ReactPaginate
previousLabel={"Prev"}
nextLabel={"Next"}
breakLabel={"..."}
pageCount={pageCount}
onPageChange={handlePageClick}
containerClassName={"pagination"}
activeClassName={"active"}
/>
</div>
);
}
export default LibraryPagination;The react-paginate library handles pagination UI and logic. I just pass the total count and a callback, and it renders a professional pagination bar.
- Use simple state-based pagination for small local datasets.
- Build a reusable component if you need pagination across multiple views.
- For API-driven apps, rely on backend pagination.
- If you want quick styling and features, use react-paginate.
When I first started building pagination, I thought it was complicated.
But once I broke it down into smaller steps, it became simple and reusable.
Try these methods in your projects, and you’ll see how much smoother your apps feel.
You may also like to read:
- Build a Custom Input Component in React
- Force a React Component to Re-Render
- Build a React Multi-Select Component
- Use componentDidMount in React Functional Components with useEffect

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.