简体   繁体   中英

StateNotifierProvider not persisting state in Flutter (Riverpod)

Basically what I am trying to do is the following: When the mobile app starts, it checks if there is an user entry existing in my local database. While checking, there is an empty yellow screen for now, indicating that it is loading / the checking is not done, yet. When done, it should show a screen, based on the users data. For that I created a StateNotifierProvider with the Riverpod package.

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

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

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

The initial state is null, but it can also be changed to a value of my screens enum (SignInScreen, EmailVerificationScreen, etc...).

Now, when starting the app, the state is null obviously, so I am showing the yellow screen. When done searching, the state changes from null to a value based on the users data. Therefore I created an if-statement before, that checks if the state is null, so that I know if there has already been an initial screen that is shown after the yellow loading screen or not and set it.

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
  )
);

But when I insert an user and the user stream is running again, it runs inside of the if-statement again, which tells me that the state is null again. After I checked the state multiple times at different spots, it always says null.

So my question now is: Why is it alaways null and not persisting the screen that I passed?

Note: After the yellow screen, it shows me the OnboardingScreen like it should, so I know that the passing of the screen to the StateNotifier works. But that does not help me when it comes to the question why it immediately changes back to null.

I found the solution by myself: Basically what seemed to cause this behaviour is that when I tried to call

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

the build method was not finished, yet.

What I had to do then was wrapping the method inside of

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM