When building a modern React application, we often need to work with large datasets. Instead of loading these large datasets all at once, applications usually fetch the data page by page. This approach is called pagination. Use of pagination can improve the application performance, reduce the load time, and can create a smoother user experience.
In this blog, we will learn how to fetch and handle the paginated data in a React application using the Tanstack Query package. We will build a simple application step by step and learn how pagination works in a real application.
What Is TanStack Query?
TanStack Query, formerly known as React Query, is a powerful data-fetching library for React. TanStack Query can help you easily fetch server data, cache the return response, and automatically handle the loading, error handling, and refetching logics. It can also manage the pagination and infinite scrolling efficiently. Instead of manually handling the api states with useEffect and useState, TanStack Query simplifies the entire process.
Why Use Pagination?
Imagine that an API is returning 10,000 users. Fetching all the data at once would result in slowing down your application and creating performance issues. It can also increase network usage. Pagination can solve these problems by loading only the data needed for the current page. This keeps the application fast and efficient.
Create a React App
First, create a React app using Vite and install the TanStack Query package.
npm create vite@latest
npm install
npm install @tanstack/react-query
Set Up QueryClient
Now we need to setup query client. Open your main.jsx or main.tsx file. The QueryClientProvider gives the app access to the Tanstack query features.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import {
QueryClient,
QueryClientProvider,
} from "@tanstack/react-query";
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById("root")).render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
Create the Fetch Function
Now we need to set up an API fetching function. Here I am using a dummy json api, for your app, update it with the actual server api. Update App.jsx file with this function.
const fetchProducts = async (page) => {
const limit = 10;
const skip = (page - 1) * limit;
const response = await fetch(
`https://dummyjson.com/products?limit=${limit}&skip=${skip}`
);
if (!response.ok) {
throw new Error("Failed to fetch products");
}
return response.json();
};Fetch Paginated Data with useQuery
Now we can fetch the data using useQuery.
import { useState } from "react";
import { useQuery, keepPreviousData } from "@tanstack/react-query";
const fetchProducts = async (page) => {
const limit = 10;
const skip = (page - 1) * limit;
const response = await fetch(
`https://dummyjson.com/products?limit=${limit}&skip=${skip}`
);
if (!response.ok) {
throw new Error("Failed to fetch products");
}
return response.json();
};
export default function App() {
const [page, setPage] = useState(1);
const { data, isPending, isError, error, isFetching } =
useQuery({
queryKey: ["products", page],
queryFn: () => fetchProducts(page),
placeholderData: keepPreviousData,
});
if (isPending) {
return <h2>Loading...</h2>;
}
if (isError) {
return <h2>{error.message}</h2>;
}
return (
<div style={{ padding: "20px" }}>
<h1>Products</h1>
{data.products.map((product) => (
<div
key={product.id}
style={{
border: "1px solid #ddd",
padding: "10px",
marginBottom: "10px",
}}
>
<h3>{product.title}</h3>
<p>${product.price}</p>
</div>
))}
<div style={{ display: "flex", gap: "10px" }}>
<button
onClick={() =>
setPage((prev) => Math.max(prev - 1, 1))
}
>
Previous
</button>
<span>Page {page}</span>
<button
onClick={() => setPage((prev) => prev + 1)}
>
Next
</button>
</div>
{isFetching && <p>Fetching new data...</p>}
</div>
);
}queryKey
queryKey: ["products", page]
The query key should change whenever the page changes. This tells the tanstack query to fetch different data for each page.
queryFn
queryFn: () => fetchProducts(page)
This function will run whenever the query key changes. When the user moves from page 1 to page 2, the query function runs with the updated page number.
keepPreviousData
placeholderData: keepPreviousData
With this feature, the previous page data stays visible, and new data loads smoothly in the background.
Pagination is an important feature in a modern React application. It is a necessary part, especially when working with APIs and large datasets. Using the Tanstack query makes this process much simpler by handling the caching, loading, and error states, background updates, and pagination logics. With a few lines of code, we can create a fast and smooth paginated ui without managing complex states manually.
To read more about Overview of React Query for Beginners, refer to our blog Overview of React Query for Beginners.