【问题标题】:StateNotifierProvider not persisting state in Flutter (Riverpod)StateNotifierProvider 不在 Flutter (Riverpod) 中保持状态
【发布时间】:2021-03-24 13:54:10
【问题描述】:

基本上我想做的是以下几点: 当移动应用程序启动时,它会检查我的本地数据库中是否存在用户条目。检查时,现在有一个空的黄色屏幕,表示它正在加载/检查尚未完成。完成后,它应该根据用户数据显示一个屏幕。 为此,我使用 Riverpod 包创建了 StateNotifierProvider。

class ChangeScreenNotifier extends StateNotifier<Screen> {
  ChangeScreenNotifier() : super(null);

  void changeTo(Screen screen) {
    state = screen;
  }
}

final initialScreenStateNotifierProvider = StateNotifierProvider<ChangeScreenNotifier>((ref) => ChangeScreenNotifier());

初始状态为 null,但也可以更改为我的屏幕枚举值(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 并且不保留我通过的屏幕?

注意:在黄色屏幕之后,它向我显示了应有的 OnboardingScreen,因此我知道将屏幕传递给 StateNotifier 是有效的。但是,当谈到为什么它立即变回 null 的问题时,这对我没有帮助。

【问题讨论】:

    标签: flutter dart riverpod


    【解决方案1】:

    我自己找到了解决方案: 基本上导致这种行为的原因是当我尝试调用时

    context.read(<ProviderName>).doSomething();
    

    构建方法还没有完成。

    然后我要做的就是将方法包装在

    WidgetsBinding.instance.addPostFrameCallback((_) => context.read(<ProviderName>).doSomething());
    

    【讨论】:

    • 这是最佳做法吗?
    • 你应该总是尽量避免这些代码行,但如果没有其他办法,那就去吧。
    猜你喜欢
    • 1970-01-01
    • 2022-09-27
    • 2022-10-25
    • 2021-12-28
    • 1970-01-01
    • 2021-04-05
    • 2022-06-11
    • 2021-05-19
    • 2022-08-14
    相关资源
    最近更新 更多