Handling Large Datasets in Ant Design: Implementing Server-Side Pagination
Stop loading thousands of rows into your browser. Learn how to implement server-side pagination in Ant Design's Table component to improve performance and handle large datasets.
09 May 2026, 00:51 UTC

The Performance Wall of Client-Side Tables
By default, the Ant Design Table component handles pagination on the client side. This means if you pass 5,000 rows into the dataSource prop, the browser must render or keep all 5,000 objects in memory, and the Table component simply slices the array for display. As your database grows, this leads to sluggish page loads, high memory consumption, and potential browser crashes.
The solution is server-side pagination: requesting only the specific slice of data needed for the current view. To do this, you must shift the Table from a "controlled" component that manages its own state to one where you explicitly tell it which page it is on and how many total records exist in the database.
Connecting Table State to API Requests
To implement server-side pagination, you need to manage three key pieces of state: the current page index, the page size (rows per page), and the total record count returned by your backend. These values are passed into the pagination prop as a configuration object.
The critical bridge is the onChange event. This callback triggers whenever a user clicks a page number or changes the page size. Instead of letting the Table slice a local array, you use this event to trigger a new API call with the updated parameters.
Implementation Example
This example assumes a React environment using Ant Design v5.x. It demonstrates how to synchronize the UI state with a mock API call.
import React, { useState, useEffect } from 'react';
import { Table } from 'antd';
const ServerTable = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [pagination, setPagination] = useState({
current: 1,
pageSize: 10,
total: 0
});
const fetchData = async (page, pageSize) => {
setLoading(true);
try {
// Replace with your actual API endpoint
// Example: /api/users?page=1&limit=10
const response = await fetch(`/api/data?page=${page}&limit=${pageSize}`);
const result = await response.json();
setData(result.items);
setPagination(prev => ({
...prev,
current: page,
pageSize: pageSize,
total: result.totalCount // Total records in DB, not just this page
}));
} catch (error) {
console.error("Fetch error:", error);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchData(pagination.current, pagination.pageSize);
}, []);
const handleTableChange = (paginationParams) => {
// paginationParams contains { current, pageSize }
fetchData(paginationParams.current, paginationParams.pageSize);
};
return (
);
};
Execution Details
- Where to run: This code resides in a React functional component.
- Permissions: Requires network access to the specified API endpoint.
- Expected Check: When clicking page "2", the
handleTableChangefunction should fire, and a network request should be visible in the browser's DevTools Network tab with the updated page parameter. - Risk: If
pagination.totalis not updated from the API response, the Table will not know how many page buttons to render, often defaulting to only one page.
Trade-offs and Race Conditions
While server-side pagination solves memory issues, it introduces a new problem: Network Race Conditions. If a user clicks page 2 and then immediately clicks page 3 before the first request finishes, the page 2 response might arrive after the page 3 response. This results in the UI showing page 3's index but page 2's data.
To prevent this, you should implement one of the following:
- AbortController: Cancel the previous fetch request whenever
fetchDatais called again. - Request IDs: Track the latest request ID and ignore responses from older IDs.
- Loading Overlays: The
loadingprop in Ant Design provides a visual cue, but it doesn't stop the network race; it only informs the user.
Verification Checklist
To ensure your implementation is working correctly, verify the following:
- API Payload: Check that the API request contains the correct
pageandlimit(pageSize) parameters. - Data Slice: Confirm that the
dataSourcecontains only the number of items specified bypageSize, not the entire dataset. - Pagination UI: Ensure the total page count in the UI matches the
totalvalue returned by the server.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.