read.cash Log in
@nolyoi more from that month

Flutter State Management - Using Provider to check if user is already logged in.

Flutter and State Management While working on the Skica app, one issue I noticed is that when closing and reopening an app, the users are asked to login every time since the login screen is the first page they're intended to see. I started thinking of different solutions. But, the one I ended up settling on was using a "wrapper" that is loaded first. This wrapper checks to see if a user is already logged in. If so, it sends them to the home page. If not, to the login. Because the Wrapper is a top-level page, we must use the Provider package (Provider is the standard for state management), to pass that information up our widget tree to the Wrapper. I will show you how this was done below. `app.dart` class App extends StatelessWidget { static FirebaseAnalytics analytics = FirebaseAnalytics(); @override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider<AuthService>(create: (_) => AuthService()), StreamProvider<User>.value( value: FirebaseAuth.instance.authStateChanges(), ), ], child: MaterialApp( home: Wrapper(), navigatorObservers: [FirebaseAnalyticsObserver(analytics: analytics)], theme: skicaTheme, ), ); } } This is the entry point to the app. As you can see, `MaterialApp` has Wrapper returned as its home option. So when the app is started, it starts by creating a `MultiProvider` widget(where we declare our different state objects) and that has a MaterialApp child.  `wrapper.dart` class Wrapper extends StatelessWidget { Wrapper({Key key}) : super(key: key); @override Widget build(BuildContext context) { final User user = Provider.of<User>(context); final AuthService authService = Provider.of<AuthService>(context); if (authService.loading) { return Spinner(); } else if (user == null) { return LoginPage(); } else { return HomePage(); } } } Our wrapper.dart is pretty simple. If the `AuthService` is loading, it gives us a loading spinner. If user, which is equal to a Provider, is null, we get the login page. Otherwise, give us the home page. Now to see how the state is passed, I will show a snippet of the Google auth in my `AuthService` class. `auth.dart` class AuthService with ChangeNotifier { bool loading = false; // Signin with Google. Future<void> signInWithGoogle() async { // See: https://firebase.flutter.dev/docs/auth/social/ loading = true; notifyListeners(); final GoogleSignInAccount googleUser = await GoogleSignIn().signIn(); if (googleUser?.authentication != null) { final GoogleSignInAuthentication googleAuth = await googleUser.authentication; final GoogleAuthCredential credential = GoogleAuthProvider.credential( accessToken: googleAuth.accessToken, idToken: googleAuth.idToken, ); await FirebaseAuth.instance.signInWithCredential(credential); } loading = false; notifyListeners(); } Here you can see that the `signInWithGoogle` function has a loading boolean set to true at the beginning of the function. This is what is being referenced in the Wrapper. The wrapper is aware of this because of the line below the loading boolean which is `notifyListeners()`. `notifyListeners()` is what notifies your Providers of the current state of something. This is why the Wrapper is able to check on the value of `authService.loading`. Because this app is integrated with Firebase Firestore, we have a nice simple way to handle social logins. If you look back to the `app.dart` file in our `MultiProvider`, you can see where the Providers are listening for the changes. `app.dart` providers: [ ChangeNotifierProvider<AuthService>(create: (_) => AuthService()), StreamProvider<User>.value( value: FirebaseAuth.instance.authStateChanges(), ), ], If there are changes, the state is made available to the widgets children. `ChangeNotifierProvider` and `StreamProvider` do behave in slightly different ways, but essentially they both make the state of something available. I know to some this may seem a bit complicated. I know it was one of the harder things for me to grasp at first. But, once you start trying to implement it yourself, it becomes a lot easier to understand. That's all for my little intro to Flutter and State!

No comments yet

Log in to join in Reading is open to everyone. Replying needs an account.