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

为何调用fetchCurrentUserData后Riverpod Provider仍无数据?

Flutter Riverpod 状态更新后在initState中无法读取数据的问题

在MaterialApp返回首页前会先执行checkLogin方法,该方法通过StreamBuilder监听Firebase Auth状态:当用户已登录时,调用userDataNotifierProvider.notifier的fetchCurrentUserData方法从Firebase获取数据,日志显示数据已成功获取并更新了Provider的state,但在BnbPages(ConsumerStatefulWidget)的initState中读取userDataNotifierProvider时,却无法获取到数据。


相关代码

checkLogin方法

Widget checkLogin() {
  loggerNoStack.i("Login checking...");
  return Consumer(builder: (context, ref, child) {
    return StreamBuilder<User?>(
      stream: _firebaseAuth.authStateChanges(),
      builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Loader();
        }
        if (snapshot.hasData) {
          user = snapshot.data;
          final uid = user?.uid;

          if (uid != null && uid.isNotEmpty) {
            return FutureBuilder(
              future: Future.wait([
                ref
                    .read(userDataNotifierProvider.notifier)
                    .fetchCurrentUserData(uid),
                ref
                    .read(userFinanceDataNotifierProvider.notifier)
                    .fetchUserFinanceData(uid),
              ]),
              builder: (context, snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  return Loader(); // Loading screen
                } else if (snapshot.hasData) {
                  if (snapshot.data != null &&
                      snapshot.data![0] &&
                      snapshot.data![1]) {
                    logger.i(
                        "Got UserData: ${snapshot.data![0] && snapshot.data![1]} and going to home screen.");
                    print("user: ${ref.read(userDataNotifierProvider).name}");
                    return BnbPages(); // User is logged in
                  } else {
                    logger.i(
                        "UserData: ${snapshot.data![0] && snapshot.data![1]} and going to auth screen.");
                    return AuthScreen();
                  }
                } else {
                  logger.i(
                      "Error getting user data: ${!(snapshot.data![0] && snapshot.data![1])} and going to auth screen.");
                  logout();
                  return const AuthScreen(); // User is not logged in
                }
              },
            );
          } else {
            logger
                .e("Error: UID is null or empty: returning to signup screen");
            return const AuthScreen();
          }
        } else {
          loggerNoStack.i("User is not signed in: to auth screen");
          return const AuthScreen();
        }
      },
    );
  });
}

UserDataNotifier代码

@riverpod
class UserDataNotifier extends _$UserDataNotifier {
  var logger = Logger(
    printer: PrettyPrinter(methodCount: 2),
  );

  @override
  UserData build() {
    // Initial empty user state
    return UserData(uid: "", name: "");
  }

  Future<bool> fetchCurrentUserData(String? uid) async {
    try {
      logger.i("checking document of: $uid");
      final docSnapshot = await userCollection.doc(uid).get();

      if (docSnapshot.exists) {
        state = docSnapshot.data()!;
        logger.i(
            "User with uid $uid found. \nUserName: ${state.userName} \nName: ${state.name} \nEmail: ${state.email} \nImage: ${state.pfpURL} \nNo of Transactios: ${state.transactionIds?.length} \nNo of Groups: ${state.groupIds?.length}");

        return true;
      } else {
        logger.w("User with uid $uid not found.");
        await FirebaseAuth.instance.signOut();
        return false;
      }
    } catch (e) {
      logger.w("Failed to fetch current user data: $e");
      return false;
    }
  }
}

BnbPages的initState代码

@override
void initState() {
  final user = ref
      .read(userDataNotifierProvider);
  print("username: ${user.userName}");
  super.initState();
}

日志输出

I/flutter (17874): ┌─────────────────────────I/flutter (17874): │ #0   UserDataNotifier.fetchCurrentUserData (package:finmate/models/user_provider.dart:29:16)
I/flutter (17874): │ #1   <asynchronous suspension>
I/flutter (17874): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter (17874): │ 💡 User with uid td7Y6DeLbiXsgem2S4yQ1M8NyUH3 found. 
I/flutter (17874): │ 💡 UserName: harsh77471 
I/flutter (17874): │ 💡 Name: Harsh Sutariya 
I/flutter (17874): │ 💡 Email: harsh@gmail.com 
I/flutter (17874): │ 💡 Image: https://firebasestorage.googleapis.com/v0/b/finmate-project.firebasestorage.app/o/users%2Fpfpics%2Ftd7Y6DeLbiXsgem2S4yQ1M8NyUH3.jpg?alt=media&token=04a025aa-5c72-4974-bf71-5d4260b56fe7 
I/flutter (17874): │ 💡 No of Transactios: 5 
I/flutter (17874): │ 💡 No of Groups: 0
I/flutter (17874): └──────────────────────────────────────────────────────────────────
I/flutter (17874): ┌───────────────────────────────────────────────────────────────
I/flutter (17874): │ 💡 User transaction data fetched successfully. 5
I/flutter (17874): └─────────────────────────────────────────────────────────────
I/flutter (17874): ┌───────────────────────────────────────────────────────
I/flutter (17874): │ #0   AuthService.checkLogin.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:finmate/services/auth_services.dart:57:30)
I/flutter (17874): │ #1   _FutureBuilderState.build (package:flutter/src/widgets/async.dart:626:55)
I/flutter (17874): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter (17874): │ 💡 Got UserData: true and going to home screen.
I/flutter (17874): └──────────────────────────────────────────────────────────
I/flutter (17874): user: 
I/flutter (17874): username: 

问题原因及解决方法

原因

  1. 状态更新通知延迟:虽然fetchCurrentUserData中已更新state,但Provider的状态更新通知可能还未传递到BnbPages,此时initState读取的仍是初始空状态。
  2. initState特性限制:initState仅在Widget初始化时执行一次,且此时Widget尚未完成与Provider的监听绑定,无法感知后续状态变化。

解决方法

方法一:用ref.watch监听状态(推荐)

在build方法中使用ref.watch,让Widget自动监听状态变化,每次状态更新都会触发build并获取最新数据:

@override
Widget build(BuildContext context) {
  final user = ref.watch(userDataNotifierProvider);
  if (user.userName.isNotEmpty) {
    print("username: ${user.userName}");
  }
  return // 页面布局代码
}

方法二:延迟读取(适用于必须在initState处理的场景)

通过Future.microtask延迟读取,确保状态更新已完成:

@override
void initState() {
  super.initState();
  Future.microtask(() {
    final user = ref.read(userDataNotifierProvider);
    print("username: ${user.userName}");
  });
}

方法三:用ref.listen监听状态变化

如果需要在状态更新时执行一次性逻辑,可以使用ref.listen:

@override
void initState() {
  super.initState();
  ref.listen<UserData>(userDataNotifierProvider, (previous, next) {
    if (next.userName.isNotEmpty) {
      print("username: ${next.userName}");
    }
  });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 08:49:50