Blog>
Snippets

Implementing Pagination with React Query and TypeScript

Illustrate how to implement pagination in a React component using React Query hooks with typed parameters for fetching and displaying paginated data.
import { useQuery } from '@tanstack/react-query';
import React, { useState } from 'react';

interface User {
  id: number;
  name: string;
}

// Define a type for the query response
interface PaginatedData {
  data: User[];
  nextPage: number | null;
}

// Fetching function with pagination support
async function fetchUsers(page: number): Promise<PaginatedData> {
  const response = await fetch(`/api/users?page=${page}`);
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
}
This part defines the TypeScript interfaces for our data, and implements the fetchUsers function, which is an asynchronous function responsible for fetching the paginated data from an API endpoint.
function Users() {
  const [page, setPage] = useState(1);
  const { data, isLoading, isError, error } = useQuery(['users', page], () => fetchUsers(page), {
    keepPreviousData: true,
  });

  return (
    <div>
      {isLoading ? (
        <p>Loading...</p>
      ) : isError ? (
        <p>Error: {error.message}</p>
      ) : (
        <>
          <ul>
            {data.data.map(user => (
              <li key={user.id}>{user.name}</li>
            ))}
          </ul>
          <button onClick={() => setPage(old => Math.max(old - 1, 1))} disabled={page === 1}>Previous Page</button>
          <button onClick={() => setPage(old => (data.nextPage != null ? old + 1 : old))} disabled={data.nextPage == null}>Next Page</button>
        </>
      )}
    </div>
  );
}
This React component uses the useState hook to manage the current page state and the useQuery hook from React Query to fetch the paginated data based on the current page. It conditionally renders loading status, error messages, the list of users, and pagination buttons.