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

Flutter中GoRouter导航失效问题求助及原因排查

GoRouter + ShellRoute 导航失效问题排查与修复

问题现象

使用GoRouter和ShellRoute开发时,仅认证失败跳转Login页面的功能正常,其余所有导航操作完全失效。已将routerConfig配置到MaterialApp中,应用全程无报错,初步怀疑与ShellRoute的key设置方式有关。

-- 更新 --
进一步排查发现:每次调用go或push跳转新路由时,GoRouter会整体重建,导致redirect逻辑被重复触发。由于GoRouter没有内置完善的Guard机制,问题根源在于redirect逻辑处理不当。

当前代码配置

MaterialApp配置

MaterialApp.router(
  debugShowCheckedModeBanner: false,
  title: 'iHub',
  theme: theme.light(settings.value.sourceColor),
  darkTheme: theme.dark(settings.value.sourceColor),
  themeMode: theme.themeMode(),
  routerDelegate: appRouter.routerDelegate,
  routeInformationProvider: appRouter.routeInformationProvider,
  routeInformationParser: appRouter.routeInformationParser,
);

GoRouter配置

final _parentKey = GlobalKey<NavigatorState>();
final _shellKey = GlobalKey<NavigatorState>();

final appRouter = GoRouter(
  initialLocation: Routes.login,
  redirect: (BuildContext context, GoRouterState state) {
    final bool isAuthenticated =
        context.read<AuthenticationBloc>().isAuthenticated;
    if (!isAuthenticated) {
      return Routes.login;
    } else {
      return Routes.dashboard;
    }
  },
  navigatorKey: _parentKey,
  routes: [
    ShellRoute(
      // 带导航栏的Shell路由
      navigatorKey: _shellKey,
      builder: (context, state, child) {
        return RootLayout(child: child);
      },
      routes: [
        GoRoute(
          name: 'dashboard',
          path: Routes.dashboard,
          pageBuilder: (context, state) => NoTransitionPage(
            key: state.pageKey,
            child: const DashboardPage(),
          ),
        ),
        GoRoute(
          name: 'documents',
          path: Routes.documentsList,
          pageBuilder: (context, state) => NoTransitionPage(
            key: state.pageKey,
            child: const DocumentsPage(),
          ),
        ),
        GoRoute(
          name: 'websites',
          path: Routes.documentsWebsitesList,
          pageBuilder: (context, state) => NoTransitionPage(
            key: state.pageKey,
            child: const WebsitesPage(),
          ),
        ),
        GoRoute(
          name: 'tasks',
          path: Routes.tasksList,
          pageBuilder: (context, state) => NoTransitionPage(
            key: state.pageKey,
            child: const ListTasksPage(),
          ),
        ),
      ],
    ),
    // 认证相关路由
    GoRoute(
      name: 'login',
      parentNavigatorKey: _parentKey,
      path: Routes.login,
      pageBuilder: (context, state) => const NoTransitionPage(
        key: ValueKey('login'),
        child: LoginPage(),
      ),
    ),
    GoRoute(
      name: 'register',
      parentNavigatorKey: _parentKey,
      path: Routes.register,
      pageBuilder: (context, state) => const NoTransitionPage(
        key: ValueKey('register'),
        child: RegisterPage(),
      ),
    ),
    // 文档相关路由
    GoRoute(
      name: 'addDocument',
      parentNavigatorKey: _parentKey,
      path: Routes.addDocument,
      pageBuilder: (context, state) => NoTransitionPage(
        key: state.pageKey,
        child: const AddDocumentPage(),
      ),
    ),
    // 网站相关路由
    GoRoute(
      name: 'addWebsite',
      parentNavigatorKey: _parentKey,
      path: Routes.addWebsite,
      pageBuilder: (context, state) => NoTransitionPage(
        key: state.pageKey,
        child: const AddWebsitePage(),
      ),
    ),
    // 任务相关路由
    GoRoute(
      name: 'addTask',
      parentNavigatorKey: _parentKey,
      path: Routes.addTask,
      pageBuilder: (context, state) => NoTransitionPage(
        key: state.pageKey,
        child: const AddTaskPage(),
      ),
    ),
    // 搜索路由
    GoRoute(
      name: 'search',
      parentNavigatorKey: _parentKey,
      path: Routes.search,
      pageBuilder: (context, state) => NoTransitionPage(
        key: state.pageKey,
        child: const SearchPage(),
      ),
    ),
  ],
);

问题修复

你的核心问题是redirect逻辑写死了跳转路径:无论当前处于什么认证后页面,只要isAuthenticated为true,就强制跳转到Routes.dashboard,导致其他导航操作被直接覆盖。

修改redirect逻辑,仅在特定场景下触发跳转,其余情况返回null放行:

redirect: (BuildContext context, GoRouterState state) {
  final bool isAuthenticated = context.read<AuthenticationBloc>().isAuthenticated;
  
  // 未认证状态,且当前不在登录/注册页面,跳转登录
  if (!isAuthenticated) {
    if (state.location != Routes.login && state.location != Routes.register) {
      return Routes.login;
    }
  } else {
    // 已认证状态,且当前在登录/注册页面,跳转首页
    if (state.location == Routes.login || state.location == Routes.register) {
      return Routes.dashboard;
    }
  }
  
  // 其他情况不跳转,返回null让GoRouter处理正常导航
  return null;
},

额外优化建议:
确保AuthenticationBloc的状态变化能触发GoRouter重新执行redirect逻辑,可以通过refreshListenable参数传入Bloc的状态监听:

// 先实现一个监听Bloc流的Listenable类
class GoRouterRefreshStream extends ChangeNotifier {
  GoRouterRefreshStream(Stream<dynamic> stream) {
    _subscription = stream.listen((_) => notifyListeners());
  }

  late final StreamSubscription<dynamic> _subscription;

  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }
}

// 在GoRouter配置中添加
final appRouter = GoRouter(
  refreshListenable: GoRouterRefreshStream(context.read<AuthenticationBloc>().stream),
  // ... 其他原有配置
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 18:47:50