为何调用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:
问题原因及解决方法
原因
- 状态更新通知延迟:虽然
fetchCurrentUserData中已更新state,但Provider的状态更新通知可能还未传递到BnbPages,此时initState读取的仍是初始空状态。 - 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
相关产品推荐
相关产品推荐

