Skip to content

Commit 652e9e0

Browse files
committed
fix(table-core): avoid no-op page index reset updates
1 parent 961258c commit 652e9e0

3 files changed

Lines changed: 131 additions & 10 deletions

File tree

.changeset/quiet-page-reset.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@tanstack/react-table': patch
3+
'@tanstack/table-core': patch
4+
---
5+
6+
Avoid emitting a pagination page-index reset when the table is already at the reset page.

packages/table-core/src/features/RowPagination.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,16 @@ export const RowPagination: TableFeature = {
215215
let registered = false
216216
let queued = false
217217

218+
const getSafePageIndex = (pageIndex: number) => {
219+
const maxPageIndex =
220+
typeof table.options.pageCount === 'undefined' ||
221+
table.options.pageCount === -1
222+
? Number.MAX_SAFE_INTEGER
223+
: table.options.pageCount - 1
224+
225+
return Math.max(0, Math.min(pageIndex, maxPageIndex))
226+
}
227+
218228
table._autoResetPageIndex = () => {
219229
if (!registered) {
220230
table._queue(() => {
@@ -254,15 +264,9 @@ export const RowPagination: TableFeature = {
254264
}
255265
table.setPageIndex = (updater) => {
256266
table.setPagination((old) => {
257-
let pageIndex = functionalUpdate(updater, old.pageIndex)
258-
259-
const maxPageIndex =
260-
typeof table.options.pageCount === 'undefined' ||
261-
table.options.pageCount === -1
262-
? Number.MAX_SAFE_INTEGER
263-
: table.options.pageCount - 1
264-
265-
pageIndex = Math.max(0, Math.min(pageIndex, maxPageIndex))
267+
const pageIndex = getSafePageIndex(
268+
functionalUpdate(updater, old.pageIndex),
269+
)
266270

267271
return {
268272
...old,
@@ -271,11 +275,20 @@ export const RowPagination: TableFeature = {
271275
})
272276
}
273277
table.resetPageIndex = (defaultState) => {
274-
table.setPageIndex(
278+
const pageIndex = getSafePageIndex(
275279
defaultState
276280
? defaultPageIndex
277281
: (table.initialState?.pagination?.pageIndex ?? defaultPageIndex),
278282
)
283+
284+
const currentPageIndex =
285+
table.getState().pagination?.pageIndex ?? defaultPageIndex
286+
287+
if (currentPageIndex === pageIndex) {
288+
return
289+
}
290+
291+
table.setPageIndex(pageIndex)
279292
}
280293
table.resetPageSize = (defaultState) => {
281294
table.setPageSize(
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { describe, expect, it, vi } from 'vitest'
2+
import {
3+
ColumnDef,
4+
createTable,
5+
functionalUpdate,
6+
getCoreRowModel,
7+
PaginationState,
8+
} from '../src'
9+
10+
type Person = {
11+
name: string
12+
}
13+
14+
const data: Person[] = [{ name: 'Ada' }]
15+
const columns: ColumnDef<Person>[] = [{ accessorKey: 'name' }]
16+
17+
function createPaginationTable(
18+
pagination: PaginationState,
19+
onPaginationChange = vi.fn(),
20+
) {
21+
const table = createTable<Person>({
22+
data,
23+
columns,
24+
getCoreRowModel: getCoreRowModel(),
25+
onPaginationChange,
26+
onStateChange() {},
27+
renderFallbackValue: '',
28+
state: {
29+
pagination,
30+
},
31+
})
32+
33+
return { table, onPaginationChange }
34+
}
35+
36+
describe('RowPagination', () => {
37+
it('does not emit a pagination change when resetting to the current page index', () => {
38+
const { table, onPaginationChange } = createPaginationTable({
39+
pageIndex: 0,
40+
pageSize: 10,
41+
})
42+
43+
table.resetPageIndex()
44+
45+
expect(onPaginationChange).not.toHaveBeenCalled()
46+
})
47+
48+
it('emits a pagination change when resetting from a different page index', () => {
49+
const { table, onPaginationChange } = createPaginationTable({
50+
pageIndex: 1,
51+
pageSize: 10,
52+
})
53+
54+
table.resetPageIndex()
55+
56+
expect(onPaginationChange).toHaveBeenCalledOnce()
57+
expect(
58+
functionalUpdate(onPaginationChange.mock.calls[0][0], {
59+
pageIndex: 1,
60+
pageSize: 10,
61+
}),
62+
).toEqual({
63+
pageIndex: 0,
64+
pageSize: 10,
65+
})
66+
})
67+
68+
it('does not emit an auto-reset pagination change when the page index is already reset', async () => {
69+
const { table, onPaginationChange } = createPaginationTable({
70+
pageIndex: 0,
71+
pageSize: 10,
72+
})
73+
74+
table._autoResetPageIndex()
75+
await Promise.resolve()
76+
77+
table._autoResetPageIndex()
78+
await Promise.resolve()
79+
80+
expect(onPaginationChange).not.toHaveBeenCalled()
81+
})
82+
83+
it('does not emit an auto-reset pagination change when core row data changes and the page index is already reset', async () => {
84+
const { table, onPaginationChange } = createPaginationTable({
85+
pageIndex: 0,
86+
pageSize: 10,
87+
})
88+
89+
table.getRowModel()
90+
await Promise.resolve()
91+
onPaginationChange.mockClear()
92+
93+
table.setOptions((old) => ({
94+
...old,
95+
data: [{ name: 'Grace' }],
96+
}))
97+
table.getRowModel()
98+
await Promise.resolve()
99+
100+
expect(onPaginationChange).not.toHaveBeenCalled()
101+
})
102+
})

0 commit comments

Comments
 (0)