Skip to content

Commit 792a9c2

Browse files
fix(table): keep rows rendered when pageSizes prop changes at runtime
Pagination's mount effect persists the initial page size into Table's internal pagination state. If a consumer later passes a different pagination.pageSizes (e.g. derived from the viewport height), the stale internal pageSize no longer matches any entry: the pageData memo's lookup loop falls through to return null and the table renders its empty state ("No data found") with data still present, recovering only on remount. Two-layer fix: - usePagination: normalize a merged pageSize that is not contained in the merged pageSizes to pageSizes[0], keeping the data slice, pager count, and currentPage clamp consistent. - Table pageData memo: replace the terminal return-null fallthrough with a defensive slice using the first available size. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent f22fb38 commit 792a9c2

3 files changed

Lines changed: 47 additions & 0 deletions

File tree

src/components/Table/Hooks/usePagination.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,18 @@ export default function usePagination(
8080
}
8181
);
8282

83+
// Normalize a stale pageSize: Pagination's mount effect persists the initial
84+
// size into inner state, so a later pageSizes prop (e.g. derived from the
85+
// viewport) may no longer contain it. Without this, the page data slice
86+
// finds no matching size and the table renders empty.
87+
if (
88+
mergedPagination.pageSizes &&
89+
mergedPagination.pageSize !== undefined &&
90+
!mergedPagination.pageSizes.includes(mergedPagination.pageSize)
91+
) {
92+
mergedPagination.pageSize = mergedPagination.pageSizes[0];
93+
}
94+
8395
// Reset `current` if data length or pageSize changed
8496
const pages: number[] = mergedPagination.pageSizes!;
8597
let maxPage: number;

src/components/Table/Table.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,16 @@ function InternalTable<RecordType extends object = any>(
579579
);
580580
}
581581
}
582+
583+
// Defensive fallback: pageSize not found in pageSizes (stale internal
584+
// state vs. an updated prop). Slice with the first available size
585+
// rather than rendering an empty table.
586+
const fallbackPageSize: number = pageSizes[0] ?? DEFAULT_PAGE_SIZE;
587+
mergedPagination.pageSize = fallbackPageSize;
588+
return mergedData.slice(
589+
(currentPage - 1) * fallbackPageSize,
590+
currentPage * fallbackPageSize
591+
);
582592
} else {
583593
if (mergedData.length < total!) {
584594
if (mergedData.length > pageSize) {

src/components/Table/Tests/Table.pagination.test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from 'react';
2+
import { act } from 'react-dom/test-utils';
23
import Enzyme, { mount } from 'enzyme';
34
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
45
import Table from '../index';
@@ -77,6 +78,30 @@ describe('Table.table-pagination', () => {
7778
expect(renderedNames(wrapper)).toEqual(['Lola']);
7879
});
7980

81+
it('keeps rendering rows when a dynamic pageSizes prop changes value', () => {
82+
// Consumers may derive pageSizes from the viewport (e.g. rows that fit the
83+
// window height). Pagination's mount effect persists the initial size into
84+
// Table's internal pagination state; a later pageSizes value must not
85+
// orphan that stale pageSize and blank the table.
86+
let wrapper;
87+
act(() => {
88+
wrapper = mount(
89+
createTable({
90+
dataSource: longData,
91+
pagination: { pageSizes: [10] },
92+
})
93+
);
94+
});
95+
wrapper.update();
96+
expect(renderedNames(wrapper)).toHaveLength(10);
97+
98+
act(() => {
99+
wrapper.setProps({ pagination: { pageSizes: [9] } });
100+
});
101+
wrapper.update();
102+
expect(renderedNames(wrapper)).toHaveLength(9);
103+
});
104+
80105
it('should not crash when trigger onChange in render', () => {
81106
function App() {
82107
const [page, setPage] = React.useState({

0 commit comments

Comments
 (0)