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

FirebaseAuth加载时,如何用Bool型Riverpod Provider配合GoRouter管理认证状态?

问题

我有一个简单的Bool型Riverpod Provider,它监听另一个返回FirebaseAuth状态变化的Provider,用于控制用户是否已登录(true或false)。当前实现如下:

返回FirebaseAuth状态变化的Stream Provider:

@riverpod
class UserAuth extends _$UserAuth {
  @override
  Stream<User?> build() {
    return FirebaseAuth.instance.authStateChanges();
  }
}

控制用户登录状态的Provider:

@riverpod
class AuthState extends _$AuthState {
  @override
  bool build() {
    final authuser = ref.watch(userAuthProvider);

    return authuser.when(
      data: (userData) {
        return true;
      },
      loading: () {
        return false;
      },
      error: (error, stackTrace) {
        return false;
      },
    );
  }
}

GoRouter Provider中的重定向逻辑:

redirect: (context, state) {
  bool authState = ref.watch(authStateProvider);
  print(authState);
  if (authState == true) {
    return '/';
  } else {
    return '/welcomepage';
  }
},

应用启动后会不断重复重定向,推测是加载状态被设为false导致的,但我只能用布尔值处理该状态,该如何解决?

解决方案

核心问题是加载阶段直接返回false触发了重定向到欢迎页,但此时Auth状态还未确定;等Stream拿到数据后又会触发重定向回首页,最终形成循环。即使只能用布尔值,我们可以通过以下方式优化:

  1. 修正AuthState的状态逻辑,避免加载阶段强制重置状态
    修改AuthState Provider,加载阶段保留当前已有状态,同时修正数据分支的判断逻辑(之前不管用户是否存在都返回true,属于逻辑错误):

    @riverpod
    class AuthState extends _$AuthState {
      @override
      bool build() {
        // 启用keepAlive防止Provider被销毁导致状态丢失
        ref.keepAlive();
        final authuser = ref.watch(userAuthProvider);
    
        return authuser.when(
          data: (userData) {
            // 只有用户存在时才返回true
            return userData != null;
          },
          loading: () {
            // 加载阶段返回当前已有的状态,而非直接返回false
            return state ?? false;
          },
          error: (error, stackTrace) {
            return false;
          },
        );
      }
    }
    
  2. 优化GoRouter重定向逻辑,避免重复跳转
    在重定向时判断当前页面是否已经是目标页面,避免无意义的重复跳转:

    redirect: (context, state) {
      final authState = ref.watch(authStateProvider);
      final currentPath = state.location;
    
      if (authState) {
        // 已经在首页就不触发重定向
        if (currentPath == '/') return null;
        return '/';
      } else {
        // 已经在欢迎页就不触发重定向
        if (currentPath == '/welcomepage') return null;
        return '/welcomepage';
      }
    },
    

    这样即使加载阶段authState为false,只要当前已经在欢迎页,就不会重复跳转;等数据加载完成后,再根据实际用户状态跳转到对应页面。

  3. 可选:提前初始化FirebaseAuth状态
    在应用启动时提前获取当前用户状态,缩短加载阶段的时长:

    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Firebase.initializeApp();
      // 提前获取初始用户状态,减少Stream加载延迟
      await FirebaseAuth.instance.authStateChanges().first;
      runApp(ProviderScope(child: MyApp()));
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 09:25:11