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

go_router中StatefulShellRoute.indexedStack登录后自定义分支不更新问题

解决GoRouter StatefulShellRoute无法根据Firebase自定义权限动态更新分支的问题

问题核心在于你当前的实现中,role是局部变量,通过ref.listen修改它不会触发routes Provider的重建,导致StatefulShellBranch的分支列表始终停留在初始化时的状态(guest角色对应的分支)。要让路由分支随用户权限动态更新,需要让routes Provider直接依赖roleProvider的状态,而非手动修改局部变量。

具体修改步骤

1. 重构路由Provider,让其依赖roleProvider

将原来的局部role变量替换为ref.watch(roleProvider),这样当用户角色变化时,routes Provider会自动重建,生成匹配当前权限的StatefulShellBranch列表:

@riverpod
GoRouter routes(RoutesRef ref) {
  // 直接监听roleProvider的状态,角色变化时自动重建GoRouter
  final role = ref.watch(roleProvider);

  return GoRouter(
    initialLocation: '/signin',
    redirect: (context, state) {
      // 保留原有redirect逻辑
      ...
      if(signinSuccess) return '/loader';
      ...
    },
    routes: [
      GoRoute(
        path: '/signin', name: 'signin',
        builder: (_, state) => const SigninView(),
      ),
      GoRoute(
        path: '/loader', name: 'loader',
        builder: (_, state) => const LoaderView(),
      ),
      StatefulShellRoute.indexedStack(
        builder: (context, state, navigationShell) {
          return ScaffoldWithNavBar(navigationShell: navigationShell, role: role);
        },
        branches: [
          StatefulShellBranch(
            routes: [
              GoRoute(
                path: '/',
                name: 'home',
                builder: (_, state) => const HomeView(),
              ),
            ],
          ),
          // 现在会根据实时role值动态生成对应权限的分支
          if (role == 'admin')
            StatefulShellBranch(
              routes: [
                GoRoute(
                  path: '/admin', name: 'admin',
                  builder: (_, state) => AdminView(),
                ),
              ],
            ),
          if (role == 'guest')
            StatefulShellBranch(
              routes: [
                GoRoute(
                  path: '/foo',
                  name: 'foo',
                  builder: (_, state) => FooView(),
                ),
              ],
            ),
        ],
      ),
    ],
  );
}

2. 修正LoaderView中的路由刷新逻辑

原来的ref.watch(routesProvider).refresh()是错误的调用方式,若需要强制路由Provider重建(实际上当路由已依赖roleProvider时,此步可省略),应使用ref.invalidate(routesProvider):

@override
Widget build(BuildContext context, WidgetRef ref) {
  ref.listen(loaderProvider, (previous, loadingDone) {
    if(loadingDone.valueOrNull == true) {
      // 可选:强制路由Provider重建(若路由已依赖roleProvider则无需此操作)
      ref.invalidate(routesProvider);
      context.goNamed('home');
    }
  });

  return Scaffold(
      body: SizedBox(...),
  );
}

为什么这样能解决问题

  • ref.watch(roleProvider)会让routes Provider订阅roleProvider的状态变化,一旦用户权限更新,Provider会立即重建,生成包含对应权限分支的新GoRouter实例。
  • 原来的ref.listen仅修改局部变量,不会触发Provider重建,所以路由分支始终停留在初始化时的版本。

内容的提问来源于stack exchange,提问作者enchance

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 01:43:11