fix(Pagination): make changeAction interruptible with optimistic page state#3131
Merged
Merged
Conversation
… state Pagination's changeAction now runs in a transition and tracks the page optimistically, matching ToggleButton. The controls reflect the page being navigated to while the action is pending, and rapid prev/next clicks advance through pages (interrupting the in-flight transition) instead of being dropped by a re-entry guard. A synchronous handler that suspends also drives the pending state. Button's clickAction keeps its single-fire guard — a re-click there is a duplicate submit, not new intent — and now documents why, with a regression test asserting a fast double-click fires clickAction only once.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
🚀 Vercel Preview Deployment
|
Contributor
PR Analysis Report📚 Storybook PreviewView Storybook for this PR 🧪 Sandbox PreviewView Sandbox for this PR No new or modified components detected. Bundle Size Summary
Accessibility AuditStatus: No accessibility violations detected. Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
…s synchronously Moving onChange into the transition deferred the consumer's page-state update (e.g. the Table pagination plugin's row slicing) to a low-priority transition commit, racing assertions under parallel CI workers. Call onChange urgently before starting the transition; the optimistic indicator and changeAction still run inside it, preserving interruptibility.
josephfarina
approved these changes
Jun 26, 2026
Condense the rationale comments added with the interruptible-action work to match the sibling ToggleButton style — explain why, not every mechanism. No logic changes.
cixzhang
commented
Jun 26, 2026
Condense the interruptible-action rationale comments to the why, dropping mechanism narration. No logic changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to the
ToggleButtonpressedChangeActionwork (#3056), applying the same review learnings to the other components with change-style actions:useOptimisticfor state: a click mid-flight should reflect the in-progress value, not the stale prop.I audited every component with an action prop. Most (
Switch,CheckboxInput,Selector,MultiSelector, date/time inputs,CheckboxList) already follow this pattern. Two stood out — handled differently here because they're semantically different.Pagination— made interruptible (the real fix)Pagination'schangeActionhad a re-entry guard (if (isDisabled || isPending) return) and didn't track the page optimistically. This is exactly the interruptible-navigation case: clicking next again while a page load is in flight was a no-op.Now:
useOptimistic, so the indicator, active page, range text, and prev/next enablement reflect the page being navigated to while the action is pending.onChange+changeActionrun inside an interruptible transition. Rapid prev/next clicks advance through pages (each click derives its target from the optimistic page) instead of being dropped.page/onChange/changeActionsignatures are unchanged.Button— guard kept on purpose, now documentedButton'sclickActionis not a state transition — it's a fire-once command (submit/save/pay). A re-click is a duplicate submit, not new intent, so theactionInFlightRefguard is correct and should stay.This matters because neither
isPendingnoruseOptimisticdedupes a same-tick double-click (neither commits synchronously), so removing the ref would let a fast double-click fireclickActiontwice. I verified this empirically. So instead of changing behavior, this adds a comment explaining why the guard exists (so it isn't "fixed" later by analogy to the toggle pattern) plus a regression test asserting a fast double-click firesclickActiononly once.Test plan
Pagination: 5 new tests — onChange→changeAction ordering, optimistic page while pending, interruption on rapid next-clicks (1→2→3), synchronous action, and disabled no-op. Full suite (48 tests) passes.Button: 1 new regression test — fast double-click firesclickActiononce. Full suite (27 tests) passes.@astryxdesign/coretypecheck, ESLint, repo sync check, and changeset check all pass.