Flutter问题:使用Go Router时热重载会返回根路由
问题解决:Flutter Provider + GoRouter 热重载返回根路由/启动页卡住
问题根源
- 在
build方法内创建AppRouter:每次热重载都会重建GoRouter实例,重置到initialLocation,直接导致跳回根路由。 - 在
build方法外创建AppRouter:GoRouter未监听AuthProvider的状态变化,即使AuthProvider的变量更新,重定向逻辑也不会触发,导致卡在启动页。
修复方案
步骤1:改造AppRouter,绑定AuthProvider并开启状态监听
class AppRouter { final AuthProvider authProvider; GoRouter get router => _goRouter; // 接收外部传入的AuthProvider AppRouter(this.authProvider); late final GoRouter _goRouter = GoRouter( // 监听AuthProvider的状态变化,自动触发重定向逻辑 refreshListenable: authProvider, initialLocation: '/', routes: <GoRoute>[ GoRoute( name: RouteNames.patientHomeScreen, path: '/', builder: (context, state) => const PatientHomeScreen(), ), GoRoute( name: RouteNames.splashScreen, path: '/splash', builder: (context, state) => const SplashScreen(), ), // 其他路由配置... ], redirect: (context, state) { // 直接使用传入的authProvider,无需重复从context获取 final isAuth = authProvider.authenticated; final isVerified = authProvider.isVerified; final isOnboard = authProvider.isOnBoarding; final isInitialize = authProvider.initialized; final loginLocation = state.namedLocation(RouteNames.loginScreen); final otpLocation = state.namedLocation(RouteNames.otpScreen); final splashScreenLocation = state.namedLocation(RouteNames.splashScreen); final onBoardScreenLocation = state.namedLocation(RouteNames.onBoardScreen); final isGoingToLogin = state.matchedLocation == loginLocation; final isGoingToInit = state.matchedLocation == splashScreenLocation; final isGoingToOnboard = state.matchedLocation == onBoardScreenLocation; final isGoingToOtp = state.matchedLocation == otpLocation; if (!isInitialize && !isGoingToInit) { return splashScreenLocation; } else if (isInitialize && !isOnboard && !isGoingToOnboard) { return onBoardScreenLocation; } else if (isInitialize && isOnboard && !isAuth && !isGoingToLogin) { return loginLocation; } else if (isInitialize && isOnboard && isAuth && !isVerified && !isGoingToOtp) { return otpLocation; } else { return null; } }, ); }
步骤2:修改MyApp,合理初始化AppRouter
将MyApp改为StatefulWidget,在依赖加载完成后初始化AppRouter,避免重复创建:
class MyApp extends StatefulWidget { MyApp({Key? key}) : super(key: key); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { late AppRouter appRouter; @override void didChangeDependencies() { super.didChangeDependencies(); // 确保能获取到已初始化的AuthProvider后再创建AppRouter final authProvider = Provider.of<AuthProvider>(context, listen: false); appRouter = AppRouter(authProvider); } @override Widget build(BuildContext context) { return MaterialApp.router( title: 'Awa', theme: TAppTheme.lightTheme, darkTheme: TAppTheme.darkTheme, // 使用routerConfig简化配置,替代分开设置三个路由相关参数 routerConfig: appRouter.router, ); } }
核心优化点
- 状态监听:通过
refreshListenable绑定AuthProvider,确保状态变化时自动触发重定向,解决启动页卡住问题。 - 避免重复实例化:在
didChangeDependencies中初始化AppRouter,避免热重载时重建GoRouter导致路由重置。 - 简化配置:使用
routerConfig替代拆分的路由参数,代码更简洁易维护。
内容的提问来源于stack exchange,提问作者saidu Bundu
相关产品推荐
相关产品推荐

