You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在事件触发时重置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 08:34:51