如何在Flutter中使用GoRouter实现首次安装用户重定向至着陆页
实现GoRouter结合Riverpod认证状态重定向的最优方案
核心思路
把GoRouter的静态定义改成通过Riverpod Provider创建,这样就能在GoRouter内部访问WidgetRef,监听认证状态变化,实现动态重定向逻辑。
步骤1:重构GoRouter为Riverpod Provider
替换原来的静态goRouter变量,用Provider提供GoRouter实例,从而在内部获取ref并监听认证状态:
final goRouterProvider = Provider<GoRouter>((ref) { // 监听认证状态,状态更新时GoRouter会自动重建 final userAsync = ref.watch(userAuthProvider); return GoRouter( initialLocation: '/', navigatorKey: _rootNavigatorKey, debugLogDiagnostics: true, // 重定向逻辑实现 redirect: (context, state) { return userAsync.when( data: (userData) { final isAuthenticated = userData != null; final isOnWelcomePage = state.location == '/welcome'; // 未登录且不在着陆页,跳转到/welcome if (!isAuthenticated && !isOnWelcomePage) { return '/welcome'; } // 已登录但在着陆页,跳转到首页 if (isAuthenticated && isOnWelcomePage) { return '/'; } // 无需重定向 return null; }, loading: () => null, // 加载状态下不重定向,后续单独处理UI error: (error, stackTrace) => null, // 错误状态可根据需求跳转到错误页 ); }, routes: [ // 添加着陆页路由 GoRoute( path: '/welcome', builder: (context, state) => const WelcomePage(), ), // 原有的嵌套路由结构 StatefulShellRoute.indexedStack( builder: (context, state, navigationShell) { return ScaffoldWithNestedNavigation(navigationShell: navigationShell); }, branches: [ StatefulShellBranch( navigatorKey: _shellNavigatorHomeKey, routes: [ GoRoute( path: '/', builder: (BuildContext context, GoRouterState state) => const MyHomePage(), routes: [ GoRoute( path: 'settimer', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const SetTimer(), ), GoRoute( path: 'countdown', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const CountDownPage(), ), ], ), ], ), StatefulShellBranch( navigatorKey: _shellNavigatorStatsKey, routes: [ GoRoute( path: '/statspage', builder: (BuildContext context, GoRouterState state) => const StatsPage(), ), ], ), StatefulShellBranch( navigatorKey: _shellNavigatorMoreKey, routes: [ GoRoute( path: '/morepage', builder: (BuildContext context, GoRouterState state) => const MorePage(), ), ], ), ], ), ], // 处理加载、错误状态的UI errorBuilder: (context, state) { return userAsync.when( data: (_) => const ErrorWidget('未知错误'), loading: () => const Center(child: CircularProgressIndicator()), error: (error, stackTrace) => ErrorWidget('认证错误: $error'), ); }, ); }); // 保留原导航键定义 final _rootNavigatorKey = GlobalKey<NavigatorState>(); final _shellNavigatorHomeKey = GlobalKey<NavigatorState>(); final _shellNavigatorStatsKey = GlobalKey<NavigatorState>(); final _shellNavigatorMoreKey = GlobalKey<NavigatorState>();
步骤2:修改MyApp使用Provider提供的GoRouter
在MyApp的build方法中,通过ref.watch获取GoRouter实例,传递给MaterialApp.router:
class MyApp extends ConsumerWidget { const MyApp({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final goRouter = ref.watch(goRouterProvider); final activetheme = ref.watch(thememodeProvider); return MaterialApp.router( title: 'Flutter Demo', routerConfig: goRouter, debugShowCheckedModeBanner: false, themeMode: activetheme, theme: MyThemes.lightTheme, darkTheme: MyThemes.darkTheme, ); } }
关键细节说明
- 状态联动:通过
ref.watch(userAuthProvider)监听认证状态,状态变化时GoRouter自动重建,保证重定向逻辑始终基于最新用户状态。 - 避免循环重定向:判断当前路径是否为目标页,防止已登录用户反复跳转到首页、未登录用户反复跳转到着陆页的问题。
- 状态反馈:在
errorBuilder中处理加载和错误状态,给用户提供明确的UI反馈,避免空白页面。 - 路由完整性:新增
/welcome路由,确保重定向目标存在,避免路由未定义错误。
内容的提问来源于stack exchange,提问作者Milan Labus
相关产品推荐
相关产品推荐

