What Is State Management?

Learn the differences and limitations of stateful widgets and Flutter state management techniques.

Stateful widgets in Flutter are used to maintain the state across one or more widgets. Then why does the stateful widget solution fall short?

Parent and child widgets

Press + to interact
Flutter widget hierarchy example
Flutter widget hierarchy example

The figure above shows us an example of a widget hierarchy in Flutter. Here, the Container is the parent widget of the Column widgets, making the Column widget a child of the Container widget. Additionally, the Column widget has three child widgets (widgets 1 to 3).

While a child widget can only have one parent widget, a parent widget can have many child widgets.

How stateful widgets work

Press + to interact
How state moves in the widget tree using stateful widgets
How state moves in the widget tree using stateful widgets

Stateful widgets work by passing state from a parent widget to its children. This state is maintained in the widget throughout the session. When the state changes, this widget and its child widgets are repainted to reflect the new state.

A child widget can have a separate state from the parent widget. This state is available only within the child widget; the parent widget isn’t able to access it. This can be good when dealing with a state that’s only accessed in one widget.

The downside of the stateful widgets

There are a few issues with stateful widgets. First, they violate the separation of concerns principle by putting the application’s logic and UI in the same file/widget. Furthermore, states in Flutter that use stateful widgets are intended to descend the widget tree. Therefore, the state of a stateful widget can only be known by its children but not by its parent widget. This complicates working with states across different widgets and may cause some widgets to know unnecessary information about the state even if they will not use it. This not only compromises the application’s security but also makes it more difficult to track down and fix bugs in the system.

Another downside is that the logic is implemented inside the widget classes, which doesn't provide a separation of concerns. For example, in the Flutter counter example code, we can see that the increment function of the counter exists inside the _MyHomePageState, as shown below:

Press + to interact
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}

Flutter state management techniques

Fortunately, many people have worked hard to address the issues presented in stateful widgets. Among these methods are the following:

  • BLoC pattern

  • Provider

  • GetIt

  • Redux

And more!

The basic idea of state management techniques

Press + to interact
Placement of logic components in state management techniques
Placement of logic components in state management techniques

Other state management strategies attempt to isolate state logic from the user interface. This makes the application more resilient and easier to debug. It also simplifies the state management code because we don’t have to repeatedly pass the state between unrelated widgets to maintain a state between them.