fix: dispatch ACTION_RESTORE synchronously after browser back/forward navigation#94139
Open
arab971 wants to merge 1 commit into
Open
fix: dispatch ACTION_RESTORE synchronously after browser back/forward navigation#94139arab971 wants to merge 1 commit into
arab971 wants to merge 1 commit into
Conversation
85fec09 to
4b22b75
Compare
… navigation Three nested deferral mechanisms caused useEffect to fire late (or never) after browser back/forward, leaving the page visually restored but functionally frozen with no errors in console: 1. `startTransition` wrapping in popstate/pushReplace handlers defers the React fiber commit as a low-priority transition 2. Dev-mode `appDevRenderingIndicator` re-wraps in `startTransition` 3. `async function runAction` forces synchronous reducer results through `.then()` microtask, deferring setState Fix: remove startTransition wrappers for ACTION_RESTORE, bypass appDevRenderingIndicator for restore actions, and make runAction synchronous. Fixes vercel#93905
4b22b75 to
fe60e80
Compare
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.
What?
Fixes browser back/forward navigation leaving the page visually restored but functionally frozen — no JavaScript executing, no errors in console, no interactivity. Fixes #93905.
Why?
Three nested deferral mechanisms prevented React from committing the fiber tree after
popstate:startTransitionwrapping in popstate/pushReplace handlers (app-router.tsx) — marks theACTION_RESTOREdispatch as a low-priority transition, deferring the React fiber commit until idle timeappDevRenderingIndicator(use-action-queue.ts) — re-wraps every dispatch in anotherstartTransitionviauseTransition, adding a second deferral layer in development modeasync function runAction(app-router-instance.ts) — forces synchronous reducer results through.then()microtask, deferringsetStateeven when the outerstartTransitionwrappers are absentThe browser bfcache restores the page visually and immediately, but React
useEffecthooks dont fire until the fiber tree commits. With three layers of deferral, the commit is indefinitely delayed — the page looks correct but is a frozen snapshot.How?
startTransitionwrapper fromonPopStateandapplyUrlFromHistoryPushReplace— dispatchACTION_RESTOREsynchronouslyappDevRenderingIndicatorforACTION_RESTOREactions — dispatch directly toactionQueue.dispatchasyncfromrunActionand theactionfunction — synchronous reducers now return plain objects,isThenablereturnsfalse, andhandleResult/setStateexecute synchronouslyThe
dispatchActionfast-path at line 160 already skipsstartTransitionand deferred promise forACTION_RESTORE— these fixes ensure that fast-path is actually reached without being defeated by outer wrappers.Verification
pnpm test-dev-turbo test/e2e/app-dir/popstate-useeffect-timing/popstate-useeffect-timing.test.ts— 2 tests passinguseEffectfires within 500ms ofhistory.back()