State Management in Flutter Part 3: Using Providers

Miguel González Doval
Barkibu Development
3 min readJan 27, 2020

--

We continue in Barkibu, our online pet care community, exploring the benefits of using Flutter continuing the posts about how to manage state.

As stated in a previous post, in Flutter you have to have a strategy to be able to change the state of a widget when another one in the tree changes, and probably one of the best approaches would be to use this Notifier/Provider management.

For the purpose of controlling the state of our app we are using a Flutter package called provider, that will give us the classes we need.

The different concepts we need to know, in order to implement it, are the following: ChangeNotifier, ChangeNotifierProvider and Provider.

Change Notifier:

This is the class in charge of sending notifications to its listeners, so that whenever something changes in the class, it sends a notification. The only method to use here is the notifyListeners one.(This would be an Observable)

class MyClass extends ChangeNotifier {
/// Class logic
notifyListeners();
}
}

Change Notifier Provider:

This widget is the one that provides an instance of Change Notifier to its descendants. Knowing that, we should use it in the first common parent of all the classes we want to notify. This is very important because the higher it is on the widget tree, the more widgets it would re-render. If placed on the main class would look like this:

void main() {
runApp(
ChangeNotifierProvider(
create: (context) => MyClass(),
child: MyApp(),
),
);
}

If you want to provide more than one class, we can do it with the widget called MultiProvider.

void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => MyClass()),
Provider(create: (context) => SomeOtherClass()),
],
child: MyApp(),
),
);
}

Consumer:

To get the state changes on the class we want, we need to use this Consumer widget, that builds itself whenever any change is notified. This widget has three params on the build method:

  • The context, used in all build methods.
  • The ChangeNotifier instance, that will change the value whenever the state changes.
  • A child attribute, that can be used to not construct the children widgets below this whenever a change happens (very useful when having some children that don’t depend on the state variable).
return Consumer<MyClass>(
builder: (context, myInstance, child) => Stack(
children: [
// Use SomeExpensiveWidget here, without rebuilding every time. This is constructed once, and out of this constructor.
child,
Text("The var is : ${myInstance.someVariable}"),
],
),
// Build the expensive widget here.
child: SomeExpensiveWidget(),
);

Provider.of

Sometimes you need to access the user interface, maybe to call a method, but you don’t need the data. By using this provider you make a change in the other widget, but you don’t reconstruct your widget because you don’t need to. To make this work, you only need to call this Provider.of, with the parameter listen to false.

Provider.of<MyClass>(context, listen: false).nonDataMethod();

What is better Notifier/Provider or BLoC?

The answer is simple, this would be as comparing a dog with an iguana, they both share some kind of topic but they are different concepts.
When using the Notifier/Provider, we are managing the way the state changes are provided throughout all the widgets in our app, but the main point of BLoC is the separation between the logic and the UI. We can (and should) use both together as they mutually complement very well.

You can check the other posts of the series!

State management in Flutter Part 1

State Management in Flutter Part 2: BLoC pattern

We are hiring

This is the state management logic we use in Barkibu. Do you like it? Are you interested in Flutter? We are hiring!.

--

--