Skip to content

fix(pagination): prevent onPaginationChange from firing when state is unchanged#6217

Open
solssak wants to merge 1 commit intoTanStack:alphafrom
solssak:fix/pagination-onchange-spurious-v2
Open

fix(pagination): prevent onPaginationChange from firing when state is unchanged#6217
solssak wants to merge 1 commit intoTanStack:alphafrom
solssak:fix/pagination-onchange-spurious-v2

Conversation

@solssak
Copy link
Copy Markdown
Contributor

@solssak solssak commented Apr 2, 2026

Summary

Fixes #6158

  • Problem: onPaginationChange fires on every URL navigation in React Server Components, even when pagination state hasn't changed. When a parent RSC re-renders (e.g., due to router.push or Link navigation), the data prop gets a new reference. This triggers _autoResetPageIndexresetPageIndexsetPaginationonPaginationChange, even though pageIndex and pageSize are identical. When pagination is persisted to URL params, this creates an infinite loop.

  • Fix: Add a shallow equality check in setPagination before invoking onPaginationChange. If the resolved new pagination state is identical to the current state, the callback is skipped entirely.

Changes

  • packages/table-core/src/utils.ts — Added shallowEqual utility function
  • packages/table-core/src/features/row-pagination/rowPaginationFeature.utils.tstable_setPagination now checks if state actually changed before calling onPaginationChange
  • packages/table-core/tests/unit/features/row-pagination/rowPaginationFeature.utils.test.ts — Added 9 tests covering no-op updates for table_setPagination, table_setPageIndex, table_resetPageIndex, and table_autoResetPageIndex

Verification

  • All 239 table-core tests pass (including 9 new ones)
  • TypeScript type check passes

Summary by CodeRabbit

  • Refactor

    • Optimized pagination state management to prevent redundant callback invocations when pagination values remain unchanged, reducing unnecessary updates and improving application performance with shallow equality checks.
  • Tests

    • Added comprehensive unit tests for row pagination utilities, including validation of pagination state updates, callback triggers, page index management, reset behavior, and default state expectations.

… unchanged

When data reference changes without actual value changes (e.g., RSC
re-renders on URL navigation), _autoResetPageIndex triggers
onPaginationChange even though pagination state is identical.

Add shallow equality check in setPagination to skip the callback when
the resolved new state matches the current state.

Closes TanStack#6158
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

The changes optimize pagination state updates by preventing unnecessary callbacks when the pagination state hasn't changed. A new shallowEqual utility was added to detect unchanged state, integrated into table_setPagination to short-circuit callback invocation, and comprehensive tests verify the optimization works across pagination update scenarios.

Changes

Cohort / File(s) Summary
Shallow Equality Utility
packages/table-core/src/utils.ts
Added shallowEqual<T> function that compares two objects by identity, key count, and property values to detect unchanged state without deep inspection.
Pagination Update Logic
packages/table-core/src/features/row-pagination/rowPaginationFeature.utils.ts
Modified table_setPagination to compute new pagination state and return early without invoking onPaginationChange callback when pagination hasn't changed via shallowEqual check.
Pagination Feature Tests
packages/table-core/tests/unit/features/row-pagination/rowPaginationFeature.utils.test.ts
Added Vitest suite validating that onPaginationChange is called only on actual state changes, covering direct updates, function updaters, setPageIndex, resetPageIndex, and autoResetPageIndex scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A shallow check saves the day,
When pagination won't budge or sway,
No callback fires for what stays the same,
The infinite loop ends its game,
History pushes, yet URLs stay sane! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the primary fix: preventing onPaginationChange callbacks when pagination state remains unchanged, which directly addresses the core issue.
Linked Issues check ✅ Passed The PR fully implements the requirements from issue #6158: adds shallow equality check to prevent onPaginationChange firing on RSC re-renders when pagination state unchanged, includes comprehensive unit tests, and eliminates the infinite loop scenario.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing issue #6158: new shallowEqual utility, pagination state update logic, and focused unit tests. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Apr 2, 2026

View your CI Pipeline Execution ↗ for commit 41f1092

Command Status Duration Result
nx affected --targets=test:eslint,test:sherif,t... ❌ Failed 1m 9s View ↗
nx run-many --targets=build -p @tanstack/table-... ✅ Succeeded 14s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-02 02:11:43 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 2, 2026

More templates

@tanstack/angular-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/angular-table@6217

@tanstack/lit-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/lit-table@6217

@tanstack/match-sorter-utils

npm i https://pkg.pr.new/TanStack/table/@tanstack/match-sorter-utils@6217

@tanstack/preact-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/preact-table@6217

@tanstack/react-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/react-table@6217

@tanstack/react-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/react-table-devtools@6217

@tanstack/solid-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/solid-table@6217

@tanstack/solid-table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/solid-table-devtools@6217

@tanstack/svelte-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/svelte-table@6217

@tanstack/table-core

npm i https://pkg.pr.new/TanStack/table/@tanstack/table-core@6217

@tanstack/table-devtools

npm i https://pkg.pr.new/TanStack/table/@tanstack/table-devtools@6217

@tanstack/vue-table

npm i https://pkg.pr.new/TanStack/table/@tanstack/vue-table@6217

commit: 41f1092

Copy link
Copy Markdown

@nx-cloud nx-cloud bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nx Cloud has identified a possible root cause for your failed CI:

We determined these failures are pre-existing issues unrelated to the pagination fix — the sherif version conflict in @tanstack/react-devtools and the ESLint import ordering error in solid-table-devtools both exist independently of this PR's changes. Neither failing project is within our touched scope (@tanstack/table-core), and no code modified by this PR is referenced in either error.

No code changes were suggested for this issue.

You can trigger a rerun by pushing an empty commit:

git commit --allow-empty -m "chore: trigger rerun"
git push

Nx Cloud View detailed reasoning on Nx Cloud ↗


🎓 Learn more about Self-Healing CI on nx.dev

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/table-core/tests/unit/features/row-pagination/rowPaginationFeature.utils.test.ts (1)

16-16: Fix array type annotation per ESLint rule.

ESLint flags the use of any[] syntax.

🔧 Proposed fix
-function createPaginationTable(onPaginationChange?: (...args: any[]) => void) {
+function createPaginationTable(onPaginationChange?: (...args: Array<any>) => void) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/table-core/tests/unit/features/row-pagination/rowPaginationFeature.utils.test.ts`
at line 16, The function signature createPaginationTable currently types the
callback parameter as onPaginationChange?: (...args: any[]) => void which
violates the ESLint rule against any[]; change the parameter to use a safer
non-any type such as onPaginationChange?: (...args: unknown[]) => void (or
Array<unknown>) so the callback accepts unknown-typed varargs instead of any,
and update any related usages/tests to handle unknown if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@packages/table-core/tests/unit/features/row-pagination/rowPaginationFeature.utils.test.ts`:
- Line 16: The function signature createPaginationTable currently types the
callback parameter as onPaginationChange?: (...args: any[]) => void which
violates the ESLint rule against any[]; change the parameter to use a safer
non-any type such as onPaginationChange?: (...args: unknown[]) => void (or
Array<unknown>) so the callback accepts unknown-typed varargs instead of any,
and update any related usages/tests to handle unknown if needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fb6ec849-e349-4d4e-b7f6-1668c5dcdcb8

📥 Commits

Reviewing files that changed from the base of the PR and between 357d582 and 41f1092.

📒 Files selected for processing (3)
  • packages/table-core/src/features/row-pagination/rowPaginationFeature.utils.ts
  • packages/table-core/src/utils.ts
  • packages/table-core/tests/unit/features/row-pagination/rowPaginationFeature.utils.test.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Event onPaginationChange is triggered on every history push in RSC

1 participant