Diagnosing Ant Design Table Server‑Side Pagination Sorting and Filtering Desynchronization
A diagnostic guide for Ant Design v5 Table server‑side pagination, sorting and filtering desynchronization: recognizable symptoms, cause table, ordered checks, fixes tied to findings, and escalation criteria.
22 Sept 2025, 19:28 UTC

Recognizable condition
The Table shows blank rows, duplicate rows, or jumps to an empty page after a filter or sorter change. Pagination controls display a total that does not match the visible rows. Rapid filter, sort or page changes cause flicker and stale data to reappear briefly.
In Ant Design v5 with CSS‑in‑JS, this is usually state desynchronization between the Table UI state and the server response, not a rendering bug. The useful takeaway is to treat pagination current, filters and sorter as a single query signature that must be reset and propagated atomically.
Cause diagnostic table
| Symptom | Likely cause | Why it happens |
|---|---|---|
| Blank rows or duplicate rows after sort/filter | Unstable or missing rowKey | React reconciles rows by key. Index or changing key causes reuse. |
| Empty page after filter change, total unchanged | Pagination current not reset | Filter reduces total pages, current page is now out of range. |
| Request sent with old params | Stale closure in fetch | Effect or callback captures previous pagination/filters/sorter. |
| Total mismatch, rows flicker | Server total inconsistent with page size or filtered set | Table trusts total for pagination UI. |
Ordered checks
1. Confirm rowKey stability
Check the Table prop rowKey is a stable unique identifier per row. It can be a string key name or a function returning a stable id.
<Table rowKey={record => record.id} ... />
Risk: using index as rowKey causes reconciliation errors on sort/filter.
2. Log onChange payload
In the component that owns the Table, log the arguments received from onChange. Run in browser console where the component renders.
const handleTableChange = (pagination, filters, sorter, extra) => {
console.log('pagination', pagination);
console.log('filters', filters);
console.log('sorter', sorter);
};
Expected check: pagination.current and pagination.pageSize reflect the UI, filters is an object keyed by column dataIndex, sorter contains field, order and column.
3. Verify fetch uses latest params
Inspect the data fetching function. Ensure it reads pagination, filters and sorter from the current render, not a captured closure.
Common pattern to avoid stale closure: derive params inside the effect that depends on them, or use functional state updates.
4. Inspect server response shape
Ant Design Table expects a data array and total for server‑side mode. Verify response matches { data: [...], total: number } and total reflects the filtered and sorted set, not the unfiltered total.
Fixes tied to findings
Stable rowKey
Provide a stable rowKey prop or function. Do not use array index.
Reset current page on filter or sorter change
When filters or sorter change, reset pagination.current to 1 before fetching. This prevents out‑of‑range requests.
const handleTableChange = (pagination, filters, sorter) => {
const isFilterOrSortChange =
JSON.stringify(filters) !== JSON.stringify(prevFiltersRef.current) ||
sorter.field !== prevSorterRef.current?.field;
const nextCurrent = isFilterOrSortChange ? 1 : pagination.current;
setPagination({ current: nextCurrent, pageSize: pagination.pageSize });
setFilters(filters);
setSorter(sorter);
};
Limitation: resetting page can be surprising for users. Consider preserving page only when total pages remain valid.
Avoid stale closures
Use functional updates or refs to ensure the fetch sees the latest query params. If using useEffect, list pagination, filters, sorter as dependencies.
Normalize server response
Map server fields to data and total consistently. Ensure total is computed after applying filters and sorting on the server.
Caution: Ant Design v4 and v5 Table APIs differ in pagination object shape and theming via ConfigProvider tokens. Server side sorting requires explicit param mapping; client side sorter defaults may silently apply if not disabled.
Verification
- Render the Table with static mock data and a stable rowKey to confirm UI renders without blank or duplicate rows.
- Add console logs in
onChangeto compare requested pagination, filters, sorter with params sent to server and response received. - Throttle network to reproduce race conditions and verify loading state and cancellation handling prevent stale responses from overwriting newer data.
CSS‑in‑JS runtime in v5 can cause perceived flicker that is styling related rather than data related. Distinguish by checking data array length vs DOM rows.
Escalation criteria
Escalate when the issue persists after rowKey stabilization and page reset, or reproduces with minimal static data. Suspected interaction with virtual list, CSS‑in‑JS style recalculation, or version‑specific Table behavior.
Escalation package should include minimal reproduction, Ant Design and React versions, and network request logs showing pagination, filters, sorter params and server responses.
Limitations
This guide covers server‑side pagination, sorting and filtering desynchronization. It does not cover client‑side data handling or custom virtual scroll implementations. Verification steps require access to the component code and network inspection.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.