StateNotifierProvider 不在 Flutter (Riverpod) 中保持状态
StateNotifierProvider not persisting state in Flutter (Riverpod)
基本上我想做的是:
当移动应用程序启动时,它会检查我的本地数据库中是否存在用户条目。检查时,目前有一个空白的黄色屏幕,表示正在加载/检查尚未完成。完成后,它应该根据用户数据显示一个屏幕。
为此,我使用 Riverpod 包创建了一个 StateNotifierProvider。
class ChangeScreenNotifier extends StateNotifier<Screen> {
ChangeScreenNotifier() : super(null);
void changeTo(Screen screen) {
state = screen;
}
}
final initialScreenStateNotifierProvider = StateNotifierProvider<ChangeScreenNotifier>((ref) => ChangeScreenNotifier());
初始状态为空,但也可以更改为我的屏幕枚举值(SignInScreen、EmailVerificationScreen 等...)。
现在,启动应用程序时,状态显然是空的,所以我显示的是黄屏。完成搜索后,状态会从 null 更改为基于用户数据的值。因此我之前创建了一个if语句,它检查状态是否为空,这样我就知道是否已经有一个初始屏幕在黄色加载屏幕之后显示并设置它。
final initialScreen = watch(initialScreenStateNotifierProvider.state);
return MaterialApp(
debugShowCheckedModeBanner: false,
supportedLocales: context.supportedLocales,
localizationsDelegates: context.localizationDelegates,
navigatorKey: Routes.sailor.navigatorKey,
onGenerateRoute: Routes.sailor.generator(),
home: StreamListener(
stream: localDatabase.streamLocalUser().map((localUser) => UserModel.fromLocalUser(localUser)),
onData: (UserModel userModel) {
print(initialScreen);
if (initialScreen == null) {
context.read(initialScreenStateNotifierProvider).changeTo(userModel == null ? Screen.OnboardingScreen : !userModel.isEmailVerified ? Screen.EmailVerificationScreen : Screen.HomeScreen);
}
print(initialScreen);
},
child: initialScreen == null ? Container(color: Colors.yellow) : initialScreen.screen
)
);
但是当我插入一个用户并且用户流再次为 运行 时,它再次在 if 语句内部运行,这告诉我状态再次为空。我在不同的地方多次检查状态后,它总是说 null.
所以我现在的问题是:为什么它总是 null 并且不保留我通过的屏幕?
注意:在黄色屏幕之后,它向我显示了 OnboardingScreen,所以我知道将屏幕传递给 StateNotifier 是有效的。但是,当谈到为什么它立即变回 null 的问题时,这对我没有帮助。
我自己找到了解决办法:
基本上导致这种行为的原因是当我试图调用
context.read(<ProviderName>).doSomething();
构建方法尚未完成。
然后我要做的就是将方法包装在
WidgetsBinding.instance.addPostFrameCallback((_) => context.read(<ProviderName>).doSomething());
基本上我想做的是: 当移动应用程序启动时,它会检查我的本地数据库中是否存在用户条目。检查时,目前有一个空白的黄色屏幕,表示正在加载/检查尚未完成。完成后,它应该根据用户数据显示一个屏幕。 为此,我使用 Riverpod 包创建了一个 StateNotifierProvider。
class ChangeScreenNotifier extends StateNotifier<Screen> {
ChangeScreenNotifier() : super(null);
void changeTo(Screen screen) {
state = screen;
}
}
final initialScreenStateNotifierProvider = StateNotifierProvider<ChangeScreenNotifier>((ref) => ChangeScreenNotifier());
初始状态为空,但也可以更改为我的屏幕枚举值(SignInScreen、EmailVerificationScreen 等...)。
现在,启动应用程序时,状态显然是空的,所以我显示的是黄屏。完成搜索后,状态会从 null 更改为基于用户数据的值。因此我之前创建了一个if语句,它检查状态是否为空,这样我就知道是否已经有一个初始屏幕在黄色加载屏幕之后显示并设置它。
final initialScreen = watch(initialScreenStateNotifierProvider.state);
return MaterialApp(
debugShowCheckedModeBanner: false,
supportedLocales: context.supportedLocales,
localizationsDelegates: context.localizationDelegates,
navigatorKey: Routes.sailor.navigatorKey,
onGenerateRoute: Routes.sailor.generator(),
home: StreamListener(
stream: localDatabase.streamLocalUser().map((localUser) => UserModel.fromLocalUser(localUser)),
onData: (UserModel userModel) {
print(initialScreen);
if (initialScreen == null) {
context.read(initialScreenStateNotifierProvider).changeTo(userModel == null ? Screen.OnboardingScreen : !userModel.isEmailVerified ? Screen.EmailVerificationScreen : Screen.HomeScreen);
}
print(initialScreen);
},
child: initialScreen == null ? Container(color: Colors.yellow) : initialScreen.screen
)
);
但是当我插入一个用户并且用户流再次为 运行 时,它再次在 if 语句内部运行,这告诉我状态再次为空。我在不同的地方多次检查状态后,它总是说 null.
所以我现在的问题是:为什么它总是 null 并且不保留我通过的屏幕?
注意:在黄色屏幕之后,它向我显示了 OnboardingScreen,所以我知道将屏幕传递给 StateNotifier 是有效的。但是,当谈到为什么它立即变回 null 的问题时,这对我没有帮助。
我自己找到了解决办法: 基本上导致这种行为的原因是当我试图调用
context.read(<ProviderName>).doSomething();
构建方法尚未完成。
然后我要做的就是将方法包装在
WidgetsBinding.instance.addPostFrameCallback((_) => context.read(<ProviderName>).doSomething());