Lifting State up and Callbacks

Kefeh Collins
Nerd For Tech
Published in
5 min readJul 28, 2021

The Chronicles of Flutter state management 4

So I wanted to write about Inherited widgets today, but realised that the concept of lifting state up and callbacks might be vital for understanding better and laying the proper foundations for inherited widgets so I am starting from here.

State management is kind of interesting, it brings more life to our code and make our programming a little more reactive.

State management with Stateful widgets and flutter hooks however, deals a little more with local states; where the state or the information that changes is only bound to one widget and is not useful (needed) anywhere else, therefore the changes to that state only affect the rebuild of only that widget which it is bound to.

But what if we need to have state that is being dependent upon by more than one widget? What if we want a state that when it changes it triggers the rebuild of all the widgets that depend on it?

Lets say for example that we have a BlueSquare Widget that displays the number of times it has been tapped, defined as seen below

where each click on the square automatically updates the text displayed with the updated total number of clicks on that square. Lets say then that we wanted to have a set of BlueSquares, that when any of them is clicked, all the blueSquares in that set display the accumulated number of clicks the user has done.

This means that, the number of clicks is not more a state that is only local to a single blueSquare object, but one that is being depended upon by many other objects and aswell can be manipulated by more than one.

So how do we go about this?

In flutter we have this concept of lifting the state up, which implies, we take that state which is being dependent upon by the set of widgets and place it as far up as the parent widget that enclose all those widgets, such that you can pass down that state to all the widgets that need it(This is similar to the concept of prop drilling for those coming from react).

Modifying our BlueSquare Widget to accept a state “drill” makes the Widget a little less complex and it does not need to be a stateful widget (as there is no local state of its own to manage).

And then we move the clicks state to the parent widget which automatically needs to be stateful as it will be managing the state.

This looks pretty good so far, all our BlueSquares have a common source of truth for their number of clicks and that’s amazing. But trying out the code, its obvious that tapping any of the blueSquare objects, we dont observe any change.

Looking at the code also, we observe that the ontap functions of each of these blueSquare objects have no functionality, and we cant just go and add a set state on it since it is now a stateless widget.

Actually what we are looking for is a way to be able to communicate with and pass information up to the parent widget when ever there is new information (such as a tap; that should update the number of taps) that will be interesting to the parent.

So how do we ensure now that a click in each of the blueSquare objects updates the clicks state and triggers the rebuild of all the other blueSquare object?

In simple terms, how can we pass up information to the parent widget?

We use callback functions, yes callback functions

Here we create a function in the parent widget and pass that function as a parameter to the child widgets, these functions use its parameters as means of injecting information. Or when called back from the child widget, it executes the code that is defined in it, in the scope of the parent widget, and it can have access to and control of the variables, parameters and state in the parent widget.

So basically, we have created a function in the main parent widget that holds all our BlueSquare widgets, the function is defined to update the value of the clicks variable inside a setState method such that it can trigger the rebuild of the parent class and subsequently all its children widgets that are dirty.

We passed the functions as a parameter to all the BlueSquare function and as used in the BlueSquare widget, it is sitting within the onTap function waiting for the user to tap it so that it is called.

This works perfectly well and helps us to handle situations such as ours that a parent widget contains data that several of its children widgets depend on and modify, which is dependent on their layout and hence a rebuild.

As we have seen, there is quite strong coupling between widgets trying to achieve non localized state management this way, where if something happens for example in the future and we dont need the BlueSquare object to display the number of clicks and we need to modify the BlueSquare widget, we will need also to modify the implementation of the Parent widget, and this can be a lot of tedious work if we had some complex kind of state and multiple levels in a big project.

Also

we can see that there starts to be to much drilling where, lets say we had a widget inside the BlueSquare widget that also needs to modify and access the number of clicks and if it goes too and sometimes some intermediate Widgets might not need the clicks value, but if a child widget does, we will need to drill the clicks value down through the intermediate value (even if it does not need it) till we reach the widget that actually needs it. This becomes a problem.

In our next article, we will be looking at how to tackle such an issue with inherited widgets.

--

--

Kefeh Collins
Nerd For Tech

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