Riverpod提供GoRouter时StatefulShellBranch报错求助
问题:Riverpod集成GoRouter+StatefulShellRoute触发路由构建错误
在Flutter项目中通过Riverpod提供GoRouter实例时,使用StatefulShellRoute会触发以下错误:
(pageBuilder != null) ^ (builder != null) One of builder or pageBuilder must be provided, but not both
但使用不含StatefulShellRoute的简单GoRouter配置时可正常运行。
相关代码实现
main函数
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); final sharedPreferences = await SharedPreferences.getInstance(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); runApp(const ProviderScope(child: MyApp())); }
根组件MyApp
class MyApp extends ConsumerWidget { const MyApp({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final goRouter = ref.watch(goRouterProvider); return MaterialApp.router( routerConfig: goRouter, title: 'ARPTC', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), ); } }
触发错误的GoRouter Provider(含StatefulShellRoute)
final goRouterProvider = Provider<GoRouter>((ref) { final rootNavigatorKey = GlobalKey<NavigatorState>(); final _shellNavigatorAKey = GlobalKey<NavigatorState>(debugLabel: 'shellA'); final _shellNavigatorBKey = GlobalKey<NavigatorState>(debugLabel: 'shellB'); return GoRouter( initialLocation: '/dashboard', navigatorKey: rootNavigatorKey, debugLogDiagnostics: true, routes: [ StatefulShellRoute.indexedStack( branches: [ StatefulShellBranch( navigatorKey: _shellNavigatorAKey, routes: [ GoRoute( path: '/a', pageBuilder: (context, state) => const NoTransitionPage( child: RootScreen(label: 'A', detailsPath: '/a/details'), ), routes: [ GoRoute( path: 'details', builder: (context, state) => const DetailsScreen(label: 'A'), ), ], ), ], ), StatefulShellBranch( navigatorKey: _shellNavigatorBKey, routes: [ GoRoute( path: '/b', pageBuilder: (context, state) => const NoTransitionPage( child: RootScreen(label: 'B', detailsPath: '/b/details'), ), routes: [ GoRoute( path: 'details', builder: (context, state) => const DetailsScreen(label: 'B'), ), ], ), ], ), ], ) ], redirect: (context, state) { // 注释的认证逻辑 }, ); });
可正常运行的简单GoRouter配置
final goRouterProviderTwo = Provider<GoRouter>((ref){ return router(ref); }); GoRouter router(ProviderRef ref) { final rootNavigatorKey = GlobalKey<NavigatorState>(); return GoRouter( initialLocation: '/courriers', navigatorKey: rootNavigatorKey, debugLogDiagnostics: true, routes: [ GoRoute( path: '/login', pageBuilder: (context, state) => const NoTransitionPage( child: LoginScreen(), ), ), GoRoute( path: '/dashboard', pageBuilder: (context, state) => const NoTransitionPage( child: DashboardPage(), ), ), GoRoute( path: '/courriers', pageBuilder: (context, state) => const NoTransitionPage( child: ListCourriersScreen(), ), ), GoRoute( path: '/courriers/:courrierId', pageBuilder: (context, state) { return NoTransitionPage( child: DetailsCourrierScreen(state.pathParameters['courrierId'] as String)); }, ), GoRoute( path: '/error', pageBuilder: (context, state) => const NoTransitionPage( child: Center( child: Text('Error'), ), ), ) ], redirect: (context, state) async { final _authState = ref.watch(authStateProvider); return _authState.when( data: (data) { User? user = data; if (user == null ){ debugPrint(":: GO TO LOGIN SCREEN"); return '/login'; } }, loading: () => '/login', error: (e, trace) => '/error'); }, ); }
问题原因与解决方法
1. 核心错误原因
错误提示明确要求:每个GoRoute必须且只能提供builder或pageBuilder中的一个。在StatefulShellRoute的分支路由体系中,所有嵌套路由必须统一使用pageBuilder——因为Shell路由基于页面栈管理状态,需要通过Page组件来维护路由栈的状态一致性,不能混用builder。
2. 额外问题:初始路径不匹配
你的initialLocation设置为/dashboard,但当前StatefulShellRoute的分支中没有该路径,会导致路由初始化失败,需要修改为分支中存在的路径(如/a)。
修正后的GoRouter Provider代码
final goRouterProvider = Provider<GoRouter>((ref) { final rootNavigatorKey = GlobalKey<NavigatorState>(); final _shellNavigatorAKey = GlobalKey<NavigatorState>(debugLabel: 'shellA'); final _shellNavigatorBKey = GlobalKey<NavigatorState>(debugLabel: 'shellB'); return GoRouter( initialLocation: '/a', // 修改为分支中存在的路径 navigatorKey: rootNavigatorKey, debugLogDiagnostics: true, routes: [ StatefulShellRoute.indexedStack( branches: [ StatefulShellBranch( navigatorKey: _shellNavigatorAKey, routes: [ GoRoute( path: '/a', pageBuilder: (context, state) => const NoTransitionPage( child: RootScreen(label: 'A', detailsPath: '/a/details'), ), routes: [ GoRoute( path: 'details', // 将builder替换为pageBuilder,用NoTransitionPage包裹 pageBuilder: (context, state) => const NoTransitionPage( child: DetailsScreen(label: 'A'), ), ), ], ), ], ), StatefulShellBranch( navigatorKey: _shellNavigatorBKey, routes: [ GoRoute( path: '/b', pageBuilder: (context, state) => const NoTransitionPage( child: RootScreen(label: 'B', detailsPath: '/b/details'), ), routes: [ GoRoute( path: 'details', pageBuilder: (context, state) => const NoTransitionPage( child: DetailsScreen(label: 'B'), ), ), ], ), ], ), ], ) ], redirect: (context, state) { // 认证逻辑可按需恢复 }, ); });
内容的提问来源于stack exchange,提问作者Armando Sudi
相关产品推荐
相关产品推荐

