Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter provider state management, logout concept

I am trying to implement custom logout solution for my application, where no matter where user currently is, once the Logout button is clicked, app will navigate back to Login page.

My idea was, that instead of listening on every component for state changes, I would have one single listener on a master component -> MyApp.

For the sake of simplicity, I have stripped down items to bare minimum. Here is how my Profile class could look like:

class Profile with ChangeNotifier {
  bool _isAuthentificated = false;
  bool get isAuthentificated => _isAuthentificated;
  set isAuthentificated(bool newVal) {
    _isAuthentificated = newVal;
    notifyListeners();
  }
}

Now, under Main, I have registered this provider as following:

void main() => runApp(
      MultiProvider(
        providers: [
          ChangeNotifierProvider(
            create: (_) => Profile(),
          )
        ],
        child: MyApp(),
      ),
    );

And finally MyApp component:

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return Consumer<Profile>(
      builder: (context, profile, _) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            brightness: Brightness.light,
            primaryColor: Color.fromARGB(255, 0, 121, 107),
            accentColor: Color.fromARGB(255, 255, 87, 34),
          ),
          home: buildBasePage(context, profile),
        );
      },
    );
  }

  Widget buildBasePage(BuildContext context, Profile currentProfile) {
    return !currentProfile.isAuthentificated
        ? LoginComponent()
        : MyHomePage(title: 'Flutter Demo Home Page test');
  }
}

My idea was, that as MyApp component is the master, I should be able to create a consumer, which would be notified if current user is authentificated, and would respond accordingly.

What happens is, that when I am in e.g. MyHomePage component and I click Logout() method which looks like following:

  void _logout() {
    Provider.of<Profile>(context, listen: false).isAuthentificated = false;
  }

I would be expecting that upon changing property, the initial MyApp component would react and generate LoginPage; which is not the case. I have tried changing from Consumer to Provider.of<Profile>(context, listen: false) yet with the same result.

What do I need to do in order for this concept to work? Is it even correct to do it this way?

I mean I could surely update my Profile class in a way, that I add the following method:

  logout(BuildContext context) {
    _isAuthentificated = false;

    Navigator.push(
        context, MaterialPageRoute(builder: (context) => LoginComponent()));
  }

And then simply call Provider.of<Profile>(context, listen: false).logout(), however I thought that Provider package was designed for this...or am I missing something?

Any help in respect to this matter would be more than appreciated.

like image 799
Robert J. Avatar asked Feb 07 '20 06:02

Robert J.


People also ask

Which state management is good for Flutter?

1. BLoC. It can be deemed the current most popular Flutter state management library of developers. It helps make the code easy to test and reusable by separating presentation from business logic.

What is MultiProvider Flutter?

MultiProvider class Null safetyA provider that merges multiple providers into a single linear widget tree. It is used to improve readability and reduce boilerplate code of having to nest multiple layers of providers.

What is ChangeNotifier Flutter?

ChangeNotifier is a class that provides change notification to its listeners. That means you can subscribe to a class that is extended or mixed in with ChangeNotifier and call its notifyListeners() method when there's a change in that class.


1 Answers

I don't know why it wasn't working for you. Here is a complete example I built based on your description. It works!

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class Profile with ChangeNotifier {
  bool _isAuthentificated = false;

  bool get isAuthentificated {
    return this._isAuthentificated;
  }

  set isAuthentificated(bool newVal) {
    this._isAuthentificated = newVal;
    this.notifyListeners();
  }
}

void main() {
  return runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider<Profile>(
          create: (final BuildContext context) {
            return Profile();
          },
        )
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return Consumer<Profile>(
      builder: (final BuildContext context, final Profile profile, final Widget child) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(primarySwatch: Colors.blue),
          home: profile.isAuthentificated ? MyHomePage() : MyLoginPage(),
        );
      },
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(final BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Home [Auth Protected]")),
      body: Center(
        child: RaisedButton(
          child: const Text("Logout"),
          onPressed: () {
            final Profile profile = Provider.of<Profile>(context, listen: false);
            profile.isAuthentificated = false;
          },
        ),
      ),
    );
  }
}

class MyLoginPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Login")),
      body: Center(
        child: RaisedButton(
          child: const Text("Login"),
          onPressed: () {
            final Profile profile = Provider.of<Profile>(context, listen: false);
            profile.isAuthentificated = true;
          },
        ),
      ),
    );
  }
}
like image 54
Ted Henry Avatar answered Oct 02 '22 12:10

Ted Henry