cloudflare / cloudflare/vinext

App Router action queue: re-render final state when a pending action is preempted by navigation (fix stale data after revalidation)

Open
#2,897 0 comments 0 reactions 0 assignees View on GitHub
nextjs-tracking
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.