State management with Provider in Flutter – Beginner tutorial

Level: Beginner.

State management is one of the most popular topic in the Flutter community, here we are going to take a look at how can we use ChangeNotifier Provider to do state management in our app, this is probably one of the easiest methods that requires the least amount of code and works really well for small – medium sized projects.

Setup

add the provider library to your pubspec.yaml file under dependencies. get latest version here

provider: ^6.0.5

run pub get to get the dependency

Building the UI

For simplicity lets create an app that changes the primary swatch color based on what option we pick:

class ChooseColorScreen extends StatelessWidget {
  const ChooseColorScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(primarySwatch: Colors.brown),
      home: Scaffold(
        appBar: AppBar(),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              MaterialButton(
                color: Colors.yellow,
                onPressed: () {},
                child: const Text("Yellow"),
              ),
              MaterialButton(
                color: Colors.red,
                onPressed: () {},
                child: const Text("Red"),
              ),
              MaterialButton(
                color: Colors.blue,
                onPressed: () {},
                child: const Text("Blue"),
              )

            ],
          ),
        ),
      ),
    );
  }
}

Now in order to change the primary swatch color we would probably have to pass a function to ‘ChooseColorScreen’ and call this function whenever we change the color, this would make our code less readable and more error prone.

instead lets use provider to manage the current color value and update the ui when the value change.

create a new directory in ‘lib’ and name it ‘provider’, inside ‘provider’ directory create a new dart file lets name this ‘color_provider‘.

in the ‘color_provider‘ create a new class ColorProvider and use the with keyword to access functions from ChangeNotifier class from the materials library.

import 'package:flutter/material.dart';

class ColorProvider with ChangeNotifier{
  
}

If you’re coming from an Android background this class will kind of end up looking like a View Model, it will hold the values for our screen and the screen will observe the values it needs and update the UI accordingly as needed.

in the ColorProvider class create a new variable to hold the current color, im going to initialize it with brown, also lets create a function to manipulate the value of the current color.

import 'package:flutter/material.dart';

class ColorProvider with ChangeNotifier{
  MaterialColor currentColor = Colors.brown;

  void changeColor(MaterialColor newColor){
    currentColor = newColor;
  }
}

Now in our ChooseColorScreen lets access our provider class, create an object of the ColorProvider using the read function from the provider package like below.

class ChooseColorScreen extends StatelessWidget {
  const ChooseColorScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // create a provider using the context of type ColorProvider
    var provider = context.read<ColorProvider>();
    return MaterialApp(
      theme: ThemeData(primarySwatch: Colors.brown),
      home: Scaffold(
        appBar: AppBar(),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              MaterialButton(
                color: Colors.yellow,
                // change onPressed to call change color function from the provider
                onPressed: () => provider.changeColor(Colors.yellow),
                child: const Text("Yellow"),
              ),
              MaterialButton(
                color: Colors.red,
                onPressed: () => provider.changeColor(Colors.red),
                child: const Text("Red"),
              ),
              MaterialButton(
                color: Colors.blue,
                onPressed: () => provider.changeColor(Colors.blue),
                child: const Text("Blue"),
              )

            ],
          ),
        ),
      ),
    );
  }
}

also in onPressed of each button don’t forget to call the changeColor function and pass the corresponding color.

the next step is to observe the current color from the provider for this we need to use the watch function instead.

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

class ChooseColorScreen extends StatelessWidget {
  const ChooseColorScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // create a provider using the context of type ColorProvider
    var provider = context.read<ColorProvider>();
    // create a watcher to get notified when something changes
    var watcher = context.watch<ColorProvider>();
    return MaterialApp(
      // use the color for the watcher
      theme: ThemeData(primarySwatch: watcher.currentColor),
      home: Scaffold(
        appBar: AppBar(),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              MaterialButton(
                color: Colors.yellow,
                // change onPressed to call change color function from the provider
                onPressed: () => provider.changeColor(Colors.yellow),
                child: const Text("Yellow"),
              ),
              MaterialButton(
                color: Colors.red,
                onPressed: () => provider.changeColor(Colors.red),
                child: const Text("Red"),
              ),
              MaterialButton(
                color: Colors.blue,
                onPressed: () => provider.changeColor(Colors.blue),
                child: const Text("Blue"),
              )

            ],
          ),
        ),
      ),
    );
  }
}

in our main function, we need to define what providers we want to use in the application, to do this we will wrap our main widget with Multiprovider, this widget takes a required parameter providers which is an array of providers since we only have one provider here we will add it like below

import 'package:provider/provider.dart';

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_)=> ColorProvider())
      ],
      child: ChooseColorScreen()
    ),
  );
}

now try running the app and notice what happens

Nothing?…

off course!, if we were working with Jetpack Compose the UI should have been updated automatically but this is Flutter XD we didn’t call the notifiyListeners function after changing the color value! this function will notify any listeners that the values have changed.

import 'package:flutter/material.dart';

class ColorProvider with ChangeNotifier{
  MaterialColor currentColor = Colors.brown;

  void changeColor(MaterialColor newColor){
    currentColor = newColor;
    // notify listeners
    notifyListeners();
  }
}

The project is available on Github.

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments