Editor’s note: This article was last updated by Joseph Mawa on 31 December 2024 to include changes to React 18 features, as well as the inclusion of Yarn 3.x.
Applications that display large amounts of data in the form of either a list or table can implement pagination to divide the data into a sequence of pages. Instead of fetching huge amounts of data from a server API at once, pagination loads data on demand, decreasing load time and improving the overall UI.
While there are many libraries available for implementing pagination, some are a bit heavy, harming your app’s overall performance. In this article, we’ll create a reusable pagination component using React hooks.
As an example, we’ll display a table of passengers in the image below using pagination. The complete code is available at the react-pagination GitHub repository; please feel free to fork it:
Before jumping into the implementation, you need basic to intermediate knowledge of React hooks. If you’re not familiar with React Hooks, first skip to the end of this article to familiarize yourself with the hooks we will use in this article before continuing with the section below.
Our goal is to display passenger data in a table using pagination. We’ll get our data from this free REST API. Begin by creating a new React application using the Create React App command below:
sh
npx create-react-app pagination-tutorial
We used npx
in the command above. All recent versions of npm
come with npx
. With npx
, you don’t need to globally install Create React App before using it to create your project.
It downloads and installs the latest version of the Create React App package into a temporary npm cache directory and runs the create-react-app
command for you. Therefore, you’ll always use the latest stable version of react scripts and React.
Currently, the latest stable release of React is version 18. Therefore, by using npx
, your application will benefit from the new React 18 features like transitions and automatic batching of state updates. In earlier React versions, batching was only limited to state updates within React event handlers.
After creating the project, remove all the default content from the App.js
file. We’ll include our code here later. The final file should look like the code below:
js
import "./App.css";
function App() {
return (
<div className="App">
{/* We will create Passengers and Pagination components and render them here */}
</div>
);
}
export default App;
Similarly, remove all the default styles in the index.css
and App.css
files in the src
directory. We’ll write our own CSS styles later.
Now, we can run the application we have just created using the command below. I’m using npm as package manager. However, you can also use yarn, or any other package manager of your choice.
sh
npm run start
We’ll use a React functional component to create a reusable pagination component. It’ll receive input from its parent component via props.
Let’s start by clarifying a few terms and variables we will use throughout the rest of the article.
Navigate to the src
directory and create a new file called Pagination.js
. Copy and paste the code below into:
js
const Pagination = (props) => {
return <div></div>;
};
export default Pagination;
Since we’re creating a reusable pagination component, it’ll get some inputs from the parent component via props. We aim to build an output like the screenshot below:
Initialize the terms we discussed in the previous section. Modify the Pagination.js
file you’ve just created to include the code below:
js
const Pagination = (props) => {
const {
currentPage,
totalPage,
pagesPerPageGroup,
handlePreviousButtonClick,
handleNextButtonClick,
handlePageChangeButtonClick,
handlePreviousPageGroupButtonClick,
handleNextPageGroupButtonClick,
} = props;
return <div></div>;
};
export default Pagination;
In the code above, we are deconstructing props that have been passed from the parent component. The prop names are pretty much self-explanatory.
To make the Pagination component reusable, it’ll only render the pagination UI. The parent component or one of its ancestors will manage the pagination state. Therefore, our Pagination
component will be a controlled component.
The Pagination component’s parent or any of its ancestors will render the data for a specific page. It’s also the parent component’s responsibility to specify the total pages, number of pages in a page group, and the current page the user is on.
Therefore, as highlighted in the code above, currentPage
, totalPage
, pagesPerPageGroup
, and the event handlers for navigating the Pagination UI will be passed from the parent component via props.
We’ll create a pagination UI that looks like the image below. The UI below is displaying a group of five pages at a time because I have set the number of pages in a page group to five. If you set it to four, the pagination UI will display four pages instead:
In the above UI, the currently active page is four. It’s highlighted using a grey background color. The minimum page limit is one and the corresponding maximum page limit is five. If we change the currently active page to six, the minimum page limit would be six and the corresponding maximum page limit would be ten as in the image below:
Next, for a given page, let’s use currentPage
, totalPage
, and pagesPerPageGroup
to create an array of page numbers to display on the pagination UI. This array will contain all the pages in a page group. We’ll then use the array to create the above UI.
Let’s declare the getCurrentPageGroup
function in the Pagination.js
file. It takes currentPage
, totalPage
, and pagesPerPageGroup
as arguments and returns an array of page numbers. The number of elements in this array depends on the number of pages in a page group:
js
const getCurrentPageGroup = (currentPage, totalPage, pagesPerPageGroup) => {
let minPageLimit =
Math.floor(currentPage / pagesPerPageGroup) * pagesPerPageGroup + 1;
if (currentPage % pagesPerPageGroup === 0) {
minPageLimit -= pagesPerPageGroup;
}
let maxPageLimit = minPageLimit + pagesPerPageGroup - 1;
if (maxPageLimit > totalPage) {
maxPageLimit = totalPage;
}
const currentPageGroup = [];
for (let i = minPageLimit; i <= maxPageLimit; i++) {
currentPageGroup.push(i);
}
return currentPageGroup;
};
To create an array of current page numbers or current page group, you can now invoke the getCurrentPageGroup
function we created above in the Pagination
component like so:
js
const Pagination = (props) => {
const {
currentPage,
totalPage,
pagesPerPageGroup,
handlePreviousButtonClick,
handleNextButtonClick,
handlePageChangeButtonClick,
handlePreviousPageGroupButtonClick,
handleNextPageGroupButtonClick,
} = props;
const currentPageGroup = getCurrentPageGroup(
currentPage,
totalPage,
pagesPerPageGroup
);
return <div></div>;
};
export default Pagination;
In the code above, the getCurrentPageGroup
function is invoked every time the Pagination
component re-renders. To avoid that, you can use the useMemo
hook to cache the result of the computation between re-renders.
With useMemo
hook, the current page group will be computed once on initial render and re-calculated in subsequent renders if one of the dependencies passed to the useMemo
hook changes:
js
const currentPageGroup = useMemo(() => {
return getCurrentPageGroup(currentPage, totalPage, pagesPerPageGroup);
}, [currentPage, totalPage, pagesPerPageGroup]);
However, in this particular use-case, useMemo
doesn’t add any noticeable performance improvement. You can execute the getCurrentPageGroup
function on every render as we did because it isn’t computationally expensive.
For a given page, the function we declared above creates the page numbers to display on the pagination UI. We are storing them in the currentPageGroup
array. Let’s now render the page group and add some navigation buttons for navigating forward and backwards. Modify the Pagination
component to return the JSX below:
js
return (
<div className="pagination-wrapper">
<ul className="ul">
<li>
<button
className="button button--border-left-radius button--border-right-none"
disabled={currentPage === 1}
>
Prev
</button>
</li>
{currentPageGroup.map((pageNumber) => {
return (
<li key={pageNumber}>
<button
className="button button--border-right-none"
style={
currentPage === pageNumber ? { backgroundColor: "gray" } : {}
}
>
{pageNumber}
</button>
</li>
);
})}
<li>
<button
className="button button--border-right-radius button--border-left-none"
disabled={currentPage === totalPage}
>
Next
</button>
</li>
</ul>
</div>
);
Let’s style the pagination UI we have created above. Create the Pagination.css
file in the src
directory. Copy and paste the styles below into it. We’re using the CSS classes assigned to the JSX elements above in the styles below. Be sure to import this CSS file into the Pagination.js
file:
css
.button {
outline: none;
border: 1px solid grey;
padding: 5px 10px;
}
.button:focus {
background-color: gray;
}
.ul {
list-style: none;
display: flex;
}
.button--border-left-radius {
border-top-left-radius: 6px;
border-bottom-left-radius: 6px;
}
.button--border-right-radius {
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
}
.button--border-right-none {
border-right: none;
}
.button--border-left-none {
border-left: none;
}
Be aware that you can also add very basic styling and leave the user of the Pagination
component to style the component as they see fit. This requires passing classes to different elements of the Pagination UI from the parent component via props.
The pagination component we have created so far will look like the image below. In the image below, currentPage
has been set to 5. You can set it to any value. At the moment, nothing will happen if you click the buttons. We’ll add event handlers shortly:
Next, let’s create ellipses dots …
, which appear when there are more pages than the current page on either the left or right. On clicking the ellipses, the user can move to either the previous or the next page group. You can see these in the image below:
If we’re displaying five pages in the pagination UI, the first page group will contain pages 1 to 5, the second page group will have pages 6 to 10, and the third will have pages 11 to 15, etc. Therefore, we don’t need the first ellipsis when displaying the first page group. Similarly, we don’t need the second ellipsis when displaying the last page group.
Let us modify the return value of the Pagination
component to conditionally render these ellipses. It will render the first ellipsis for all page groups except the first and render the second ellipsis for all page groups except the last:
jsx
return (
<div className="pagination-wrapper">
<ul className="ul">
<li>
<button
className="button button--border-left-radius button--border-right-none"
disabled={currentPage === 1}
>
Prev
</button>
</li>
{/* First ellipsis */}
{currentPageGroup[0] > pagesPerPageGroup ? (
<li>
<button className="button">…</button>
</li>
) : null}
{currentPageGroup.map((pageNumber) => {
return (
<li key={pageNumber}>
<button
className="button button--border-right-none"
style={
currentPage === pageNumber ? { backgroundColor: "gray" } : {}
}
>
{pageNumber}
</button>
</li>
);
})}
{/* Second ellipsis */}
{currentPageGroup[currentPageGroup.length - 1] !== totalPage ? (
<li>
<button className="button">…</button>
</li>
) : null}
<li>
<button
className="button button--border-right-radius button--border-left-none"
disabled={currentPage === totalPage}
>
Next
</button>
</li>
</ul>
</div>
);
Our pagination UI is now complete but the buttons aren’t interactive. We need to add interactivity by declaring click event handlers.
Remember, the previous button takes you to the previous page. Assuming you’re on the sixth page of our Pagination
component, clicking the Prev button will direct you to the fifth page, and the Pagination UI will display pages 1 to 5.
As explained above, the role of the Pagination
component is to create and render the Pagination UI. The parent component or one of its ancestors will manage the Pagination state. Therefore, the parent component will pass the handlePreviousButtonClick
event handler to the Pagination
component via props.
This event handler takes the event
object and the current page group as arguments. We’ll invoke it when the user clicks the Prev button. Because the parent component is managing the pagination state, it already has access to the currentPage
, totalPage
, and pagesPerPageGroup
state variables.
Let’s declare the _handlePreviousButtonClick
event handler. In this event handler, we will invoke handlePreviousButtonClick
with the event
object and currentPageGroup
as arguments:
js
const _handlePreviousButtonClick = (event) => {
handlePreviousButtonClick(event, currentPageGroup);
};
You can then add the above click event handler to the Prev button. You’ll notice that the Prev button is disabled when we’re on the first page:
jsx
return (
<div className="pagination-wrapper">
<ul className="ul">
<li>
<button
className="button button--border-left-radius button--border-right-none"
disabled={currentPage === 1}
onClick={_handlePreviousButtonClick}
>
Prev
</button>
</li>
{ /*....*/ }
<li>
<button
className="button button--border-right-radius button--border-left-none"
disabled={currentPage === totalPage}
>
Next
</button>
</li>
</ul>
</div>
);
};
Now our previous button is interactive if you render the Pagination
component. If you’re on page two, clicking the previous button will take you to page one. Instead of declaring and adding the event handler as we did in the example above, you can also declare it inline.
Unlike the Prev button, the Next button will take you to the next page. Assuming you’re on the fifth page, clicking Next will take you to the sixth page and the Pagination UI will display pages 6 to 10. Similar to the Prev button, the Next button is disabled if you’re on the last page.
Let’s declare another click
event handler in the Pagination
component and call it _handleNextButtonClick
. In this event handler, we’ll invoke the handleNextButtonClick
function passing the event
object and currentPageGroup
as arguments:
js
const _handleNextButtonClick = (event) => {
handleNextButtonClick(event, currentPageGroup);
};
The handleNextButtonClick
was passed to the Pagination
component via props. After invoking it, the parent component will update state and display data for the current page.
Like with the Prev button, a conditional check is not necessary because the Next button is disabled if you’re on the last page. You can now register the _handleNextButtonClick
event handler on the Next button like so:
jsx
return (
<div className="pagination-wrapper">
<ul className="ul">
<li>
<button
className="button button--border-left-radius button--border-right-none"
disabled={currentPage === 1}
onClick={_handlePreviousButtonClick}
>
Prev
</button>
</li>
{ /*....*/ }
<li>
<button
className="button button--border-right-radius button--border-left-none"
disabled={currentPage === totalPage}
onClick={_handleNextButtonClick}
>
Next
</button>
</li>
</ul>
</div>
);
};
The Next button should now be functional if you render the Pagination
component. If you’re on the first page, clicking Next will take you to the second page.
At the moment, you can only use the Prev and Next buttons to navigate from one page to another. As an example, if you’re on page one and want to navigate to page five, you’ll have to navigate sequentially through the intermediate pages by repeatedly clicking the Next button.
This is not only tedious but inefficient because the parent component will attempt to fetch and render the corresponding data for the intermediate pages. Therefore, a user should be able to navigate to a specific page by clicking the page number on the pagination UI.
Let’s declare another click event handler for switching directly to specific page numbers. In this event handler, we will invoke handlePageChangeButtonClick
function with the event
object and currentPageGroup
as arguments. The handlePageChangeButtonClick
function was passed from the parent component via props:
js
const _handlePageChangeButtonClick = (event) => {
handlePageChangeButtonClick(event, currentPageGroup);
};
You can now register the above click event handler on the page buttons as in the code below. We’re also setting the page number as the id
attribute so that we can retrieve it in the event handler in the parent component:
jsx
return (
<div className="pagination-wrapper">
<ul className="ul">
{/* ... */}
{currentPageGroup.map((pageNumber) => {
return (
<li key={pageNumber}>
<button
className="button button--border-right-none"
style={
currentPage === pageNumber ? { backgroundColor: "gray" } : {}
}
id={pageNumber}
onClick={_handlePageChangeButtonClick}
>
{pageNumber}
</button>
</li>
);
})}
{/* ... */}
</ul>
</div>
);
Instead of declaring the above event handler as we did, you can also declare it inline.
Remember, if the pagination UI isn’t displaying the first page group, we need to display an ellipsis just after Prev button to indicate that certain pages have been omitted. We remove it when displaying the first page group.
We want to navigate to the previous page group when a user clicks the first ellipsis. Clicking it doesn’t do anything at the moment. Let’s declare the _handlePreviousPageGroupButtonClick
event handler in the Pagination
component. In this event handler, we will invoke its corresponding event handler passed from the parent component:
js
const _handlePreviousPageGroupButtonClick = (event) => {
handlePreviousPageGroupButtonClick(event, currentPageGroup)
};
You can now register the above function as the click event handler for the first ellipsis:
jsx
return (
<div className="pagination-wrapper">
<ul className="ul">
{/* ... */}
{currentPageGroup[0] > pagesPerPageGroup ? (
<button
className="button"
onClick={_handlePreviousPageGroupButtonClick}
>
…
</button>
) : null}
{/* ... */}
</ul>
</div>
);
The first ellipsis is now interactive if you render the Pagination
component. Clicking it will navigate you to the previous page group.
When the pagination UI is not displaying the last page group, we display a second ellipsis just before Next button to indicate that some pages have been omitted.
The second ellipsis is similar to the first. However, unlike the first, clicking the second ellipsis will take you to the next page group. Let’s declare the _handleNextPageGroupButtonClick
event handler in our Pagination
component:
js
const _handleNextPageGroupButtonClick = (event) => {
handleNextPageGroupButtonClick(event, currentPageGroup);
};
In the above event handler, we’re invoking the corresponding event handler passed from the parent via props. You can now register the click event handler on the second ellipsis like so:
jsx
return (
<div className="pagination-wrapper">
<ul className="ul">
{/* ... */}
{currentPageGroup[0] > pagesPerPageGroup ? (
<li>
<button
className="button"
onClick={_handlePreviousPageGroupButtonClick}
>
…
</button>
</li>
) : null}
{/* ... */}
{currentPageGroup[currentPageGroup.length - 1] !== totalPage ? (
<li>
<button className="button" onClick={_handleNextPageGroupButtonClick}>
…
</button>
</li>
) : null}
{/* ... */}
</ul>
</div>
);
The displayed ellipses are now interactive if you render the Pagination
component. You can navigate forward to the next page group and backward to the previous page group.
Our pagination component is now complete and interactive. Let’s use it in our project. The image below show how we can break down our final application into simple React components:
We have already declared App
and Pagination
components. However, we have yet to declare the Passengers
component. This component will be responsible for displaying our passenger data in tabular format. As the above image illustrates, both Passengers
and Pagination
components will be children of the App
component.
Navigate to the src
directory and create the Passengers.js
file. Copy and paste the code below into it. The Passengers
component accepts the passenger data via props and represent them in a table. You can represent them in any format you like:
js
import "./Passengers.css";
const Passengers = ({ passengersData }) => {
return (
<>
<h1>Passengers</h1>
<div className="table-wrapper">
<table>
<thead>
<tr>
<th>Name</th>
<th>Trips</th>
<th>Airline</th>
<th>Country</th>
</tr>
</thead>
<tbody>
{passengersData.map((data) => (
<tr key={data._id}>
<td>{data.name}</td>
<td>{data.trips}</td>
<td>{data.airline[0].name}</td>
<td>{data.airline[0].country}</td>
</tr>
))}
</tbody>
</table>
</div>
</>
);
};
export default Passengers;
Let’s add a bit of styling to our table so that it is more readable. In the code above, we imported the Passengers.css
file but we haven’t created it yet. Create the Passengers.css
file in the src
directory. Copy and paste the styles below into it. You can also style the table the way you like:
css
.table-wrapper {
background-color: hsl(207, 85%, 97%);
border-radius: 5px;
margin: 10px 0;
overflow: auto;
}
table {
border-collapse: collapse;
width: 100%;
}
ul {
margin: 0;
padding: 0;
}
h1{
margin: 0;
}
td,
th {
border: 1px solid hsl(210, 8%, 90%);
padding: 5px;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
You can copy and paste the styles below into the App.css
file in the src
directory. It will center the Passengers
and Pagination
components:
css
.App {
min-height: 95vh;
margin: 10px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
Finally, navigate to the parent component responsible for fetching data from the API and managing our Pagination state. In our case, it is the App
component. It’ll render the Passengers
and Pagination
components we created above. Modify the App.js
file in the src
directory to include the code below:
js
import { useEffect, useState } from "react";
import "./App.css";
import Pagination from "./Pagination";
import Passengers from "./Passengers";
function App() {
const [passengersData, setData] = useState([]);
const [totalPage, setTotalPage] = useState(50);
const [currentPage, setCurrentPage] = useState(1);
const handlePreviousButtonClick = (event, currentPageGroup) => {
setCurrentPage((currentPage) => currentPage - 1);
};
const handleNextButtonClick = (event, currentPageGroup) => {
setCurrentPage((currentPage) => currentPage + 1);
};
const handlePreviousPageGroupButtonClick = (event, currentPageGroup) => {
setCurrentPage(currentPageGroup[0] - 1);
};
const handleNextPageGroupButtonClick = (event, currentPageGroup) => {
setCurrentPage(currentPageGroup[currentPageGroup.length - 1] + 1);
};
const handlePageChangeButtonClick = (event, currentPageGroup) => {
setCurrentPage(Number(event.target.id));
};
useEffect(() => {
fetch(
`https://api.instantwebtools.net/v1/passenger?page=${currentPage}&size=5`
)
.then((response) => response.json())
.then((json) => {
setData(json.data);
setTotalPage(json.totalPages);
});
}, [currentPage]);
return (
<div className="App">
<Passengers passengersData={passengersData} />
<Pagination
totalPage={totalPage}
currentPage={currentPage}
pagesPerPageGroup={5}
handlePreviousButtonClick={handlePreviousButtonClick}
handleNextButtonClick={handleNextButtonClick}
handlePageChangeButtonClick={handlePageChangeButtonClick}
handlePreviousPageGroupButtonClick={handlePreviousPageGroupButtonClick}
handleNextPageGroupButtonClick={handleNextPageGroupButtonClick}
/>
</div>
);
}
export default App;
When the current page changes, we fetch data from our API and update state in the useEffect
hook. React will batch state updates in the .then
callback to avoid unnecessary re-renders. Both state updates will trigger a single render.
React 18 will automatically batch state updates in event handlers, promises, and setTimeout.
In the code above, we are importing Pagination
and Passengers
components and passing them the appropriate props. The Passengers
component accepts only one prop, the passengersData
.
On the other hand, we’re passing currentPage
, totalPage
, pagesPerPageGroup
, and event handlers for updating pagination state to the Pagination
component via props. The Pagination
component will use the data to create the Pagination UI. As the user interacts with the UI, it’ll invoke the appropriate event handlers.
If your data component makes complex updates or renders large datasets, your pagination UI or the entire application may feel unresponsive on slow devices during the rendering process.
Therefore, you can mark the setData(json.data)
state update in the useEffect
hook a non-blocking transition. You can do so either using the setTransition function or the useTransition hook. It’ll ensure your Pagination UI remains responsive during heavy rendering processes:
js
import { startTransition } from "react";
useEffect(() => {
fetch(url)
.then((response) => response.json())
.then((json) => {
startTransition(() => {
setData(json.data);
});
setTotalPage(json.totalPages);
});
}, [currentPage]);
This feature was introduced in React 18. Therefore, it isn’t available in earlier React versions. We haven’t used it in the application we built above because our data component renders a simple dataset.
This section will briefly explain some of the hooks that have been highlighted in this article.
useState
hookIf you’d like to add state to your functional component, the useState
hook will do the job. Consider the example below:
js
// a new state variable called "currentPage"
const [currentPage, setCurrentPage] = useState(1);
The useState
hook helps to preserve state between re-renders. It takes a single argument, which is the initial state. In the example above, the currentPage
state variable is initially set to 1
. The useState
hook will return a pair of values, the first being the state value, and the second is the function to set the state.
We’ll use the useState
hook to maintain the state for the current page as well as hold the response data from the passenger API.
useEffect
hookIf you’d like to perform any side effects like data fetching, DOM manipulation, or subscribing and unsubscribing to events, the useEffect
hook will help you:
js
useEffect(()=>{
// call rest api
},[]);
React has access to the state of your component, so it’ll essentially remember the function you passed and invoke it after DOM updates. In this article, we used the useEffect
hook to fetch passenger data from the REST API.
useMemo
hookThis is a hook you can use to cache the result of a computationally expensive operation between re-renders.
js
const cachedValue = useMemo(calculateValue, arrayOfDependencies)
The useMemo
hook takes two arguments. The first argument is a pure function that takes no arguments and returns the value you want to calculate. This can be any JavaScript value. The second argument to the useMemo
hook is an array of dependencies that you reference in the function passed as first argument.
In the example below, the dependencies are currentPage
, totalPage
, and pagesPerPageGroup
because they’re all referenced in the function we passed as first argument.
js
const currentPageGroup = useMemo(() => {
return getCurrentPageGroup(currentPage, totalPage, pagesPerPageGroup);
}, [currentPage, totalPage, pagesPerPageGroup]);
The useMemo
hook is a performance enhancement hook. Only use it if the computation you want to cache is noticeably slow and you’re certain it’ll improve performance.
useTransition
hookThe useTransition
hook shipped with React 18. You can use it to mark some state updates as non-blocking transitions. Such state updates will ensure your UI remains responsive during the rendering process.
The useTransition
hook takes no argument and returns an array of two entries:
js
const [isPending, startTransition] = useTransition();
The first entry in the array returned by the useTransition
hook is a flag that determines whether there’s a pending transition. The second entry is a function you can use to mark specific state updates as non-blocking transition:
js
startTransition(() => {
setData(json.data);
});
In this tutorial, we created a reusable pagination component from the ground up using React hooks. The pagination component’s parent or any of its ancestors is responsible for managing the pagination state.
The data and event handlers the pagination component needs to construct the pagination UI are passed from the parent component via props. As the user interacts with the pagination UI by navigating from one page to the next, the corresponding event handlers are invoked by the pagination component so that its parent or its ancestor responsible for managing the pagination state can fetch the corresponding data to display.
While we developed our example application using React, you can apply the same logic to any framework. I hope you learned something new! Be sure to leave a comment if you have any questions. Happy coding!
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowThe beta version of Tailwind CSS v4.0 was released a few months ago. Explore the new developments and how Tailwind makes the build process faster and simpler.
ChartDB is a powerful tool designed to simplify and enhance the process of visualizing complex databases. Explore how to get started with ChartDB to enhance your data storytelling.
Learn how to use JavaScript scroll snap events for dynamic scroll-triggered animations, enhancing user experience seamlessly.
A comprehensive guide to deep linking in React Native for iOS 14+ and Android 11.x, including a step-by-step tutorial.
3 Replies to "React pagination from scratch using hooks"
Hi, This is great article about pagination.
What if, we wanted to show the button to show last page and first page
Hi, Although the approach for creating pagination is great and easy. I’m bit concerned about what will happen if current page won’t load then we will end up showing current page on UI but with the old data.
IMHO It would be great if we just set current page once page data is fetched. and in next and previous calls we just increment and decrement current page with a local variable.
There is bug with the code on github
fetch(`https://api.instantwebtools.net/v1/passenger?page=${currentPage}&size=5`) instead of
fetch(`https://api.instantwebtools.net/v1/passenger?currentPage=${currentPage}&size=5`)
in teh file Passenger.js