Providers (An introduction)

The Chronicles of Flutter state management 6.

Kefeh Collins
Geek Culture
5 min readAug 18, 2021

--

If you have been following up with the progression of state management so far up to inherited widgets, here is a basic summary of what it is all about

  • We have some state
  • We have a way to provide it or make it available to all widgets that need it
  • We have a way to update the state and trigger rebuilds of widgets using (consuming) the states.

That is basically it in tandem.

The evolution and existence of new and multiple state management approaches are as a result of programmers wanting the ability to maintain good software development practices, either because not doing so makes code readability and maintainability tedious or simply because we want to. But either way, enforcing these principles is usually very vital and at the core of programming best practices.

Last time, we looked at Inherited widgets and no matter how good its solution is, we couldn’t help but cringe at the fact that there were too many boilerplate codes. These boilerplate range from; explicitly defining conditions for which a difference in a previous state value to the current state should trigger a rebuild of the consuming widgets, to having a whole stateful widget that triggers the rebuild of the state enclosing class (inherited widget) that in turn trigger the rebuild of the consuming widgets if certain conditions are met (what a cycle).

In essence, Inherited widgets are just widgets that hold data, and the data is available for reference and use by the widget the inherited widget is wrapped around and all the Widgets descendants. Inherited widgets also provide a means by which all Widgets (only those) that are consuming or using it’s value are rebuilt in cases where that value changes.

When we looked at the inherited widgets we created, we realize that it contained only one state variant

What if we decided to have more than one?

But looking at the solution critically, if clicks should change, both widgets that are consuming exclusively clicks and exclusively size will be rebuilt and vise versa, which we don’t want as it causes unnecessary rebuilds of widgets.

Trying to tackle this means swapping our InheritedWidget dependence for a dependence on a new class called the inherited model.

And using it as

This just screams more boilerplate and is difficult to understand (we don’t want that). It seems to be a lot of work and code to get simple things done. (I am not going to dive deep into InheritedModels, it is used only for representation — pass across a point — purposes in the article).

So how can we achieve the same fit but using less code?

We use providers.

Providers is a package that was created as a wrap around on the InheritedWidget. It is popular because, it uses the same syntax as inherited widgets hence maintaining some sense of consistency. It also has other advantages as it solves the Inherited Widgets problems of

  • Having too much boilerplate code (which is cumbersome and difficult to maintain)
  • Having too much nested code, which makes inherited widgets difficult to factorize and can be confusing.
  • Nesting hell, when we have more than a few InheritedWidgets that we want to use or wrap a single widget.

Lets therefore take a look at how to use this package, first to provide data around the widget tree and then in subsequent write-ups how to notify for changes and trigger rebuilds (with ChangeNotifiers and StateNotifiers).

Provider is an external flutter package that you will need to install (add to your pubspec.yaml file) by following the instructions here https://pub.dev/packages/provider/install

Once done, lets see how to provide data. For context, we have a BlueSquare widget, which is a blue square that displays the number of clicks on all instance of the BlueSquare objects, defined as with inherited widget.

The inherited widget as defined in the gist here

To provide the clicks variable to our BlueSquare widgets, lets start by creating a “state” class to hold the value.

And with providers, we do

Being used as

As seen above, we can see that our Provider class has a type that in this case is our “state” class; ClicksState and take a create parameter which is simply a function that takes in a BuildContext and returns the Object of the “state” class.

When consuming the data, the provider class has the of<T>() method that simply looks up the tree above the widget it is invoked in for the instance of T, in our case T represents ClicksState. Once it finds it, it accesses the data or information being requested, hence providing the data for which it is used to expose.

This approach can be useful in the sense that, you can use a provider as such to pass data between widgets; data that doesn't need to change (sometimes pass data between pages of the app or something like that). But for our case we need the state to change, so how can we go about this?

We will in the next two parts of the write-up see how to handle changing state data with ChangeNotifiers and then with StateNotifiers.

This ends our introduction to provider, see you in the next one.

--

--

Kefeh Collins
Geek Culture

An Enthusiastic problem solver, uses code as a tool for problem solving.