Flutter State Management (Provider)

26th October 2021


Page Index


    The State of an application is simply information stored in the memory, which can be accessed from anywhere across your application.

    How State and Its Changes Behave in Flutter?

    The best answer to the question is Flutter is Declarative.

    Flutter builds its user interface to reflect the current state of your app.

    When the state of your app changes (for example, the user flips a switch in the settings screen), you change the state, and that triggers a redraw of the user interface. There is no imperative changing of the UI itself (like widget.setText)—you change the state, and the UI rebuilds from scratch.

    Let's Use a Simple State Management Approach

    • Provider: A package for state management, built with widgets. It purposefully uses widgets for DI/state management instead of dart-only classes. The reason is, widgets are very simple yet robust and scalable.

    Let's add the dependency to our pubspec.yaml first:

    name: Counter
    description: Simple Counter app.
    # ...
        sdk: flutter
      provider: ^4.0.5
      # ...

    Now you can import 'package:provider/provider.dart'and start building.

    3 Key Concepts to Understand

    • ChangeNotifier
    • ChangeNotifierProvider
    • Consumer

    Consider, we are going to make a simple counter app and Counter is our model class.


    A simple class provides change notifications to its listeners. The only code that is specific to ChangeNotifier is the call to notifyListeners().

    class Counter with ChangeNotifier {
      int value = 0;
      void increment() {
        value += 1;

    The call notifyListeners() tells the widgets, which are listening to this model to rebuild.


    ChangeNotifierProvider is the widget that provides an instance of a ChangeNotifier to its descendants.
    We need to put ChangeNotifierProvider above the widgets that need to access.

    void main() {
          create: (context) => Counter(),
          child: MyApp(),

    If you have more than one class to provide, there is MultiProvider.

    void main() {
          providers: [
            ChangeNotifierProvider(create: (context) => Counter()),
            Provider(create: (context) => SomeOtherClass()),
          child: MyApp(),


    Our Counter is provided to widgets through ChangeNotifierProvider declaration; we can start using it through Consumer widget.

        builder: (context, counter, child) => Text('${counter.value}'

    We must specify the type of the model that we want to access. In this case, we want Counter, so we write Consumer<Counter>. If you don’t specify the generic (<Counter>), the provider package won’t be able to help you.

    If you don't really need the data, but to call a method, we don't need to use Consumer because, we’d be asking the framework to rebuild a widget that doesn’t need to be rebuilt.

    For this use case, we can use Provider.of, with the listen parameter set to false.

    For our Increment button:

    floatingActionButton: FloatingActionButton(
            onPressed: () =>
                Provider.of<Counter>(context, listen: false).increment(),
            tooltip: 'Increment',
            child: Icon(Icons.add),

    The complete source code is in GitHub.

    There are other approaches like Redux, BLoC/Rx, MobX for app state management.
    You can learn more at Flutter.dev.

    About the Author

    Related Blogs

    View All Blogs

    Want #swag?

    Join our monthly raffle!

    Every month, One Lucky Duck gets free swag shipped to their doorstep, wherever in the world you are! All you have to do is join our Discord channel today and tweet about the amazing things we do. #nullcast #luckyduck

    We will announce the winners on Twitter and through our discord channel.