cloudflare / cloudflare/vinext
App Router action queue: re-render final state when a pending action is preempted by navigation (fix stale data after revalidation)
- Dominant language
- TypeScript
- Stars
- 8.8k
- Forks
- 406
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 120
Description
## Upstream change
Next.js [1e113cf](https://github.com/vercel/next.js/commit/1e113cf5cdbb3662e858658dfd5d524af143d306) — "Fix stale data after navigation despite revalidation" (#95439)
## The bug
The App Router action queue always updates React state in dispatch order. When a navigation **displaces** (preempts) a pending server action, the navigation's promise is the last one dispatched. So when the preempted action later runs — even if it revalidated data — its resulting state is no longer reflected on screen, because the navigation's state was published last. Result: the UI shows stale data after navigation despite a successful revalidation.
## The fix
In `packages/next/src/client/components/app-router-instance.ts`:
- Add a `wasPreempted?: boolean` flag to `AppRouterActionQueue`.
- When a pending action is discarded because a navigation takes priority (`actionQueue.pending.discarded = true`), also set `actionQueue.wasPreempted = true`.
- In `runRemainingActions`, once the queue is idle (`pending === null`) and `wasPreempted` was set, clear the flag and publish the final queue state: `startTransition(() => setState(actionQueue.state))`. The existing `needsRefresh` flush now runs alongside this.
## Why it's relevant to vinext
vinext reimplements App Router client-side navigation and the server-actions dispatch queue. If vinext's action queue does not re-render the final state after a preempting navigation, users will see stale data after a navigation that interrupts a revalidating action — matching the upstream bug.
## Action
- Check vinext's App Router action-queue implementation for equivalent preemption handling (navigation displacing a pending action).
- Ensure the final queue state is re-published once the queue drains after a preemption, so revalidated data is reflected.
- Port the regression test (`actions-discarded-navigation-revert`) which was red before the fix.
## References
- Commit: https://github.com/vercel/next.js/commit/1e113cf5cdbb3662e858658dfd5d524af143d306
- PR: https://github.com/vercel/next.js/pull/95439
Contributor guide
Research direction
Inspect vinext's App Router action-queue implementation for navigation preemption, then run the existing actions-discarded-navigation-revert regression test if present. Compare its behavior with the upstream change and verify that, after a navigation displaces a pending action, the final queue state is re-published when the queue drains and the regression test passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- next.js, react, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100