Flutter中Navigator.push后GoRouter.go失效问题及混合路由调用可行性咨询
嗨,我懂这种踩坑的郁闷——用原生Navigator.push打开页面后,再调用GoRouter.go居然纹丝不动,完全没跳转到目标页面对吧?我来给你掰扯清楚这个问题,顺便说说能不能混合用这俩路由方式。
先还原下你遇到的问题场景
- 操作步骤:
- 调用
Navigator.of(context).push(MaterialPageRoute(builder: (_) => SomePage()))打开页面 - 接着调用
GoRouter.of(context).go('/anywhere')
- 调用
- 预期结果:成功跳转到
/anywhere对应的页面 - 实际结果:页面还停留在
SomePage,完全没反应
为啥会出现这种情况?
核心原因是GoRouter和原生Navigator的路由栈是分层的:
GoRouter是基于Navigator 2.0实现的路由管理框架,它自己维护了一套独立的路由状态栈。当你用原生Navigator.push时,这个页面其实是被推到了GoRouter管理的Navigator栈之上的一个“额外栈层”,GoRouter的路由状态里根本没记录这个页面的存在。
这时候你调用GoRouter.go,它只会更新自己管理的那部分路由栈,但最顶层的那个由原生Navigator push的页面还“盖”在上面,所以你自然看不到GoRouter跳转后的页面。
那能不能混合调用Navigator和GoRouter?
可以,但非常不推荐长期这么做,很容易造成路由状态混乱,后期维护起来会头大。如果是临时需要这么处理,给你几个思路:
最优解:统一用GoRouter的API
把所有原生Navigator.push的调用替换成GoRouter的context.push()或者对应方法,保持整个App的路由管理统一,从根源上避免这种分层栈的问题。这也是官方推荐的做法。临时方案:先pop掉原生push的页面再跳转
如果必须用原生Navigator打开页面,之后要调用GoRouter跳转时,先把原生栈的页面移除:// 先把原生push的页面pop掉 Navigator.of(context).pop(); // 再调用GoRouter的方法 context.go('/page1');这样GoRouter管理的路由栈就会成为顶层,跳转就能正常生效了。
用GoRouter的navigatorKey操作根Navigator
你可以在初始化GoRouter时传入一个navigatorKey,之后通过这个key获取根Navigator,这样push的页面会纳入GoRouter的路由上下文:final GlobalKey<NavigatorState> _rootNavigatorKey = GlobalKey<NavigatorState>(); // 初始化GoRouter时传入 GoRouter( navigatorKey: _rootNavigatorKey, // ...其他配置 ) // 用根Navigator push _rootNavigatorKey.currentState?.push(MaterialPageRoute(builder: (_) => Page2()));不过就算这样,还是建议尽量统一用GoRouter的API,减少状态不一致的风险。
附上你提供的示例代码(方便对照)
import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: GoRouter( initialLocation: '/page1', routes: [ GoRoute(path: '/page1', builder: (_, __) => Page1()), GoRoute(path: '/page2', builder: (_, __) => Page2()), ], ), ); } } class Page1 extends StatelessWidget { const Page1({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text('Page 1', textAlign: TextAlign.center), TextButton( onPressed: () { context.go('/page2'); }, child: Text('GoRouter.go Page 2'), ), TextButton( onPressed: () { context.push('/page2'); }, child: Text('GoRouter.push Page 2'), ), TextButton( onPressed: () { final nav = Navigator.of(context); nav.push(MaterialPageRoute(builder: (_) => Page2())); }, child: Text('Navigator.push Page 2'), ), ], ), ); } } class Page2 extends StatelessWidget { const Page2({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text('Page 2', textAlign: TextAlign.center), TextButton( onPressed: () { context.go('/page1'); }, child: Text('GoRouter.go Page 1'), ), TextButton( onPressed: () { GoRouter.of(context).pop(); }, child: Text('GoRouter.pop'), ), ], ), ); } }
内容来源于stack exchange

