[go_router] Fix pop() restoring stale configuration when route has onExit#11241
[go_router] Fix pop() restoring stale configuration when route has onExit#11241dkajiwara wants to merge 2 commits intoflutter:mainfrom
Conversation
…has onExit When a route has onExit, _handlePopPageWithRouteMatch defers the pop to a microtask. Calling restore() immediately with the pre-pop currentConfiguration can trigger async redirects that overwrite the eventual pop result. Detect synchronous completion by comparing currentConfiguration identity before and after the pop call, avoiding any mutable flag on the delegate.
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
There was a problem hiding this comment.
Code Review
This pull request fixes an issue where GoRouter.pop() could restore a stale configuration when a route has an onExit handler, which could lead to the popped route reappearing. The fix cleverly uses an identical() check to ensure restore() is only called for synchronous pops where the configuration has actually changed. The changes are well-supported by new regression tests that cover the fixed scenario and related edge cases. My review includes one suggestion to enhance a code comment for better long-term maintainability.
| // Only restore when the pop completed synchronously (no onExit). | ||
| // If deferred, currentConfiguration is still the same instance. |
There was a problem hiding this comment.
The current comment explains the condition well. To further improve maintainability, consider adding a brief note about why this check is important, mentioning the risk of restoring a stale configuration. This will help future developers understand the full context and prevent accidental regressions.
// Only restore on a synchronous pop to avoid restoring a stale configuration.
// A deferred pop (e.g. due to an async `onExit`) would leave the
// `currentConfiguration` instance unchanged, and restoring it could cause issues.
GoRouter.pop()unconditionally calledrestore()afterrouterDelegate.pop(). When the route hasonExit, the pop is deferred to a microtask, sorestore()was called with the pre-pop configuration. This caused async redirects to overwritethe post-pop state, making the popped route reappear.
Fixed by comparing
currentConfigurationidentity before and after pop.restore()is only called when the configuration was actually updated (synchronous pop).Fixes flutter/flutter#174525 flutter/flutter#180002
Pre-Review Checklist
[shared_preferences]///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2