Open eli1stark opened 4 months ago
It seems that the go_router API is not truly synchronous, as stated in the documentation, which can lead to issues like this. The asynchronous behavior is hidden behind the API, and the client assumes that it's synchronous. In this case, it seems a race condition occurs between
goNamed
andshowDialog
.Adding some arbitrary delay between calls fixes the issue, but this is not a great solution because you can never know what is a sufficient time needed to await
go
andgoNamed
to avoid the issue on all devices and platforms.
@eli1stark This issue once resolved will also solve your case. Please check the same and confirm if you can follow-up in it.
This is different, they are awaiting for result of the page, which won't get completed until the page is popped, if I understand it correctly, at least this is how push
and pushNamed
works and they want to introduce a similar concept to go
and goNamed
.
The problem here is that go_router
jumps into racing condition with Navigator 1.0 (when I push dialog) which makes it incompatible for certain use cases like mine. A first solution would be to make execution of go
and goNamed
truly synchronous, there is no reason for them to be asynchronous behind the curtains, a 2nd solution is to add ability to push dialogs and bottom sheets through go_router
API, so it can queue properly calls and avoid racing conditions.
If we go with the 2nd case docs should state that go_router
is not fully compatible with the Navigator 1.0 and everything must be done through go_router
API. If I call router.go
and then call immediately router.push
it works as expected and page is pushed correctly, however it's not the same if I mix the calls with Navigator 1.0 like showDialog
or showModalBottomSheet
and so on.
Here are examples where the router is racing or incompatible with Navigator 1.0 (I abstracted the examples a little bit for simplicity):
GoRouter.go('A')
GoRouter.push('B') // works (page 'B' is shown)
GoRouter.go('A')
Navigator.push('B') // doesn't work (page 'B' is not shown)
GoRouter.go('A')
Navigator.showDialog() // doesn't work (dialog is not shown)
GoRouter.go('A')
Navigator.showModalBottomSheet() // doesn't work (bottom sheet is not shown)
GoRouter.push('B')
Navigator.pop() // doesn't work (There is nothing to pop is thrown)
Navigator.push('B')
Navigator.pop() // works (page 'B' is popped without issues)
In all occurrences where it doesn't work it should work, otherwise go_router
docs should mention incompatibility issues with Navigator 1.0.
GoRouter leverages the Router API to provide backward compatibility with the Navigator, so any calls to Navigator.of(context).push() or Navigator.of(context).pop() will continue to work, but these destinations aren't deep-linkable. You can gradually add more routes to the GoRouter configuration.
Thanks for the update. I was able to replicate the reported behavior.
Yes, I think we should do something about this.
I'm running into the same issue but in reverse - in my case I have a bottom navigation bar which uses goNamed to switch "tabs" on one of the tabs I use "showModalBottomSheet" which does not cover the bottom navigation, so when I tap a nav item the bottomSheet is still shown, AND the route changes behind it which is quite confusing. Would expect goNamed to pop the modal bottom sheet.
Steps to reproduce
It seems that the go_router API is not truly synchronous, as stated in the documentation, which can lead to issues like this. The asynchronous behavior is hidden behind the API, and the client assumes that it's synchronous. In this case, it seems a race condition occurs between
goNamed
andshowDialog
.Adding some arbitrary delay between calls fixes the issue, but this is not a great solution because you can never know what is a sufficient time needed to await
go
andgoNamed
to avoid the issue on all devices and platforms.Expected results
Dialog must be shown.
Actual results
Dialog is not shown.
Code sample
Code sample
```dart import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; final router = GoRouter( routes: [ GoRoute( name: 'A', path: '/', builder: (_, __) => const PageA(), ), GoRoute( name: 'B', path: '/B', builder: (_, __) => const PageB(), ), ], ); void main() => runApp(const App()); class App extends StatelessWidget { const App({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: router, ); } } class PageA extends StatelessWidget { const PageA({super.key}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: TextButton( onPressed: () { context.pushNamed('B'); }, child: const Text('Go to page B'), ), ), ], ), ); } } class PageB extends StatelessWidget { const PageB({super.key}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey, body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: TextButton( onPressed: () { final ctx = router.routerDelegate.navigatorKey.currentContext!; ctx.goNamed('A'); showDialog( context: ctx, builder: (_) => const AlertDialog( title: Text('Dialog Title'), content: Text('This is my content'), ), ); }, child: const Text('Go Page A and Show dialog'), ), ), ], ), ); } } ```Flutter Doctor output
Doctor output
```console Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 3.16.7, on macOS 14.2.1 23C71 darwin-arm64, locale en-US) [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0) [✓] Xcode - develop for iOS and macOS (Xcode 15.3) [✓] Chrome - develop for the web [✓] Android Studio (version 2022.3) [✓] VS Code (version 1.87.2) [✓] Connected device (4 available) [✓] Network resources • No issues found! ```