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

基于GoRouter与Riverpod Providers的Flutter Web全局导航问题

问题解决:GoRouter + Riverpod + Firebase Auth 导航异常

问题背景

整合Firebase Auth、Riverpod与GoRouter后,Web端点击导航项时出现错误:

"Another exception was thrown: Navigator.onGenerateRoute was null, but the route named "/preloginhome" was referenced."

核心问题是错误使用全局NavigatorKey进行导航,而非通过GoRouter实例调用导航方法,导致GoRouter的路由解析逻辑未生效。

错误原因

当前通过key.currentState!.pushNamed()跳转路由,但GoRouter有独立的路由管理体系,全局NavigatorKey无法关联GoRouter的路由配置,从而触发路由解析失败的错误。

解决方案

1. 移除全局NavigatorKey(可选但推荐)

GoRouter不需要依赖全局NavigatorKey实现导航,可直接从routerProvider获取实例操作:

final routerProvider = Provider<GoRouter>((ref) {
  final authState = ref.watch(authStateProvider);

  return GoRouter(
    debugLogDiagnostics: true,
    initialLocation: SplashPage.routeLocation,
    routes: [
      GoRoute(
        path: SplashPage.routeLocation,
        name: SplashPage.routeName,
        builder: (context, state) => const SplashPage(),
      ),
      GoRoute(
        path: '/preloginhome',
        name: 'preloginhome',
        builder: (context, state) => const PreLoginHome(),
      ),
      GoRoute(
        path: '/dashboard',
        name: 'dashboard',
        builder: (context, state) => const Dashboard(),
      ),
      // 其他路由配置
    ],
    // 可选:添加登录状态自动重定向逻辑
    redirect: (context, state) {
      final isLoggedIn = authState != null;
      final targetLocation = state.location;

      // 未登录用户访问非预登录页面,重定向到预登录首页
      if (!isLoggedIn && targetLocation != '/preloginhome' && targetLocation != SplashPage.routeLocation) {
        return '/preloginhome';
      }
      // 已登录用户访问预登录页面,重定向到仪表盘
      if (isLoggedIn && targetLocation == '/preloginhome') {
        return '/dashboard';
      }
      return null;
    },
  );
});

2. 修改CustomAppBar的导航逻辑

通过Riverpod获取routerProvider实例,调用GoRouter原生的pushNamed方法跳转:

class CustomAppBar extends ConsumerWidget implements PreferredSizeWidget {
  const CustomAppBar({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final router = ref.watch(routerProvider);
    // 用Riverpod监听的auth状态判断登录,保持状态一致性
    final authState = ref.watch(authStateProvider);
    final isUserSignedIn = authState != null;

    return AppBar(
      title: TextButton(
        onPressed: () {
          isUserSignedIn 
              ? router.pushNamed('dashboard') 
              : router.pushNamed('preloginhome');
        },
        child: Text(
          'Agroopet',
          style: TextStyle(
            fontSize: 22,
            color: Theme.of(context).colorScheme.onSurface,
          ),
        ),
      ),
      // 其他AppBar配置项
    );
  }

  @override
  Size get preferredSize => const Size.fromHeight(kToolbarHeight);
}

关键说明

  • 使用GoRouter实例的pushNamed/goNamed方法:pushNamed会将新路由加入历史栈,goNamed会替换当前路由栈,根据需求选择。
  • 用Riverpod的authStateProvider判断登录状态:与routerProvider监听的状态保持一致,避免直接调用FirebaseAuth.instance导致的状态不一致问题。
  • 优先使用路由name跳转:相比直接写path,路由name更稳定,后续修改path时无需同步修改跳转代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:10:28