如何在事件触发时重置GoRouter的StatefulShellBranch路由状态
解决StatefulShellRoute.indexedStack登出后分支状态残留问题
问题核心
StatefulShellRoute.indexedStack会缓存每个分支的页面实例和导航栈状态,单纯调用popUntil只能移除当前分支的路由栈,但切换回分支时,indexedStack会复用之前缓存的页面,导致用户专属内容(如/a/details)依然保留未登出前的状态。
解决方案
1. 让GoRouter监听登录状态实现全局刷新
将userAuthProvider设置为GoRouter的refreshListenable,登录状态变化时自动触发路由刷新和重定向:
final goRouter = GoRouter( initialLocation: '/a', navigatorKey: _rootNavigatorKey, // 监听auth状态变化,触发路由全局刷新 refreshListenable: userAuthProvider, redirect: (context, state) { final isLoggedIn = userAuthProvider.isLoggedIn; // 登出时,强制跳回对应分支的初始路由 if (!isLoggedIn) { if (state.location.startsWith('/a') && state.location != '/a') { return '/a'; } if (state.location.startsWith('/b') && state.location != '/b') { return '/b'; } } return null; }, routes: [/* 原有路由配置 */], );
2. 监听登录状态,重置所有分支导航栈并强制跳转初始路由
在ScaffoldWithNestedNavigation的build方法中,监听登录状态变化,调用goBranch重置每个分支的状态:
ref.listen(userAuthProvider, (previous, next) { if (!next.isLoggedIn) { // 遍历所有分支,强制跳转到初始路由并清空导航栈 for (int i = 0; i < navigationShell.route.branches.length; i++) { navigationShell.goBranch(i, initialLocation: true); } // 切换回默认的初始分支(如/a) navigationShell.goBranch(0); } });
3. 给分支根页面添加动态Key,强制重建页面
因为indexedStack会缓存页面实例,需要通过动态Key让页面在登录状态变化时重建:
class RootScreen extends ConsumerWidget { final String label; final String detailsPath; const RootScreen({super.key, required this.label, required this.detailsPath}); @override Widget build(BuildContext context, WidgetRef ref) { final authState = ref.watch(userAuthProvider); // 用登录状态作为Key的一部分,状态变化时Key更新,触发页面重建 final screenKey = ValueKey('root-$label-${authState.isLoggedIn}'); return Scaffold( key: screenKey, appBar: AppBar(title: Text('Screen $label')), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('Screen $label', style: Theme.of(context).textTheme.titleLarge), const SizedBox(height: 16), ElevatedButton( onPressed: () => context.go(detailsPath), child: const Text('View Details'), ), ], ), ), ); } }
原有方案无效原因
原有代码仅调用popUntil清空导航栈,但indexedStack仍保留着分支页面的实例,切换回分支时会直接复用该实例,不会重建页面。结合goBranch(initialLocation: true)和动态Key,才能彻底重置分支状态并刷新页面内容。
内容的提问来源于stack exchange,提问作者dizziness
相关产品推荐
相关产品推荐

