Flutter GoRouter同路由栈传递不同extra参数的解决方案
解决GoRouter嵌套路由不同类型Extra参数冲突问题
错误原因分析
你遇到的类型转换错误,本质是跳转嵌套子路由时,父路由的state.extra被意外替换为子路由传入的NewProposalBloc实例,导致父路由中state.extra as Trip的类型转换失败。这是因为当父路由和子路由共用同一个parentNavigatorKey时,GoRouter会覆盖整个路由栈的上下文参数,引发类型冲突。
最优解决方案:利用Bloc上下文传递(无需Extra传参)
既然NewProposalBloc是在NewProposalPage1中创建的,直接通过Bloc的上下文传递即可,无需借助extra,同时确保子路由嵌套在父路由的栈中:
- 修改路由定义
移除子路由的parentNavigatorKey,让子路由归属于父路由的导航栈,同时删除子路由对extra的依赖:
GoRoute( path: '/new-proposal-page1', parentNavigatorKey: _rootNavigatorKey, pageBuilder: (context, state) => CupertinoPage( child: NewProposalPage1(trip: state.extra as Trip), ), routes: [ GoRoute( path: 'new-proposal-page2', // 移除parentNavigatorKey,确保子路由在父路由栈中 pageBuilder: (context, newProposalState) => const CupertinoPage( child: NewProposalPage2(), ), ), ] ),
- 在子页面中获取Bloc实例
在NewProposalPage2中直接通过上下文获取父页面提供的NewProposalBloc:
class NewProposalPage2 extends StatelessWidget { const NewProposalPage2({super.key}); @override Widget build(BuildContext context) { // 从上下文直接获取Bloc实例 final newProposalBloc = BlocProvider.of<NewProposalBloc>(context); return BlocProvider.value( value: newProposalBloc, child: // 你的页面内容 ); } }
- 父页面跳转逻辑
跳转子路由时无需传递extra,直接使用相对路径:
// 在NewProposalPage1中触发跳转 context.push('new-proposal-page2');
备选方案:隔离父路由参数(保留Extra传参)
如果一定要通过extra给子路由传参,可以将父路由的Trip参数保存到页面状态中,避免依赖state.extra的动态变化:
- 修改NewProposalPage1
class NewProposalPage1 extends StatefulWidget { final Trip trip; const NewProposalPage1({super.key, required this.trip}); @override State<NewProposalPage1> createState() => _NewProposalPage1State(); } class _NewProposalPage1State extends State<NewProposalPage1> { late final NewProposalBloc _bloc; @override void initState() { super.initState(); // 使用widget.trip初始化Bloc,而非依赖state.extra _bloc = NewProposalBloc(trip: widget.trip); } @override void dispose() { _bloc.close(); super.dispose(); } @override Widget build(BuildContext context) { return BlocProvider.value( value: _bloc, child: Scaffold( // 跳转时传递Bloc作为extra floatingActionButton: FloatingActionButton( onPressed: () => context.push('new-proposal-page2', extra: _bloc), ), ), ); } }
- 子路由保留原定义
此时父路由的state.extra as Trip仅在页面初始化时执行一次,后续即使extra被替换为Bloc,页面已通过widget.trip保存了原始参数,不会触发类型转换错误。
内容的提问来源于stack exchange,提问作者Lewandossi
相关产品推荐
相关产品推荐

