Hi, Habr! I submit a translation of the article,
let me help you understand and choose a state management solution for your app that interested me in the process of learning the basics of state management in Flutter. I will be glad to hear any criticism regarding this translation. In the return quotes (``) my personal thoughts and explanations will be written.

Flutter status management is a hot topic. There are many possible solutions to the problem and getting lost in them, choosing the most suitable one for your needs is extremely simple. I myself was confused, but I found the right solution. Let me share it with you.
To find a solution that fits your needs, you need to determine your own needs. In my case it is:
- Have the opportunity to develop the project without compromising the quality of the code
- Separate display logic from business logic
- Have a clear code that is hard to break.
- Predictable and clear code
Given these requirements, suitable options remain:
')
- Using the
setState()
method and setState()
widgets - `Library` ScopedModel
- Apply the BLoC pattern (Components of business logic)
- Redux
Difference between local and global state
Before diving into the analysis of selected solutions, it is necessary to understand the difference between the local and global state. A practical example is suitable for this:
Imagine an authorization form, where the user is prompted to enter a username and password and get the object "user identity" after submitting the form. In this example, any verification of the data entered in the form fields will be part of the local state of the 'authorization form widget`, and the rest of the application should not be aware of this. And the “personality” object returned by the `authorization server` is a part of the global state. So how other components depend on this object that change the behavior depending on whether the user is authorized.
Brief conclusions for those who are tired of waitingIf you do not want to wait, or are not interested in my research, here is a brief overview of the results:

My recommendation is to use BLoC to manage the local state and Redux for the global state, especially if you are creating a complex application that will grow with time.
Why you should not use setState ()
Using
setState()
inside your widgets is great for quickly creating prototypes and getting feedback on these changes, but this way does not help us achieve our goals, because the display logic is mixed with business logic, which violates the principle of purity and quality of the code. Maintenance of this code will be difficult in the future, therefore, except for prototyping, this approach is not recommended.
ScopedModel - step in the right direction
ScopedModel is a third-party library by
Brian Egan . It allows you to create special
Models
objects, as well as use the
notifyListeners()
method when necessary. For example, to track on any change in the property of a model object:
class CounterModel extends Model { int _counter = 0; int get counter = _counter; void increment() { _counter++; notifyListeners(); } }
In our widgets, we will be able to respond to changes in the model using the
ScopedModelDescendant
widget `provided by this
ScopedModelDescendant
:
class CounterApp extends StatelessWidget { @override Widget build(BuildContext context) { return new ScopedModel<CounterModel>( model: new CounterModel(), child: new Column(children: [ new ScopedModelDescendant<CounterModel>( builder: (context, child, model) => new Text('${model.counter}'), ), new Text(" , CounterModel") ]) ); } }
In contrast to the use of the
setState()
approach, this solution allows us to separate the display logic from the business logic. However, it imposes certain restrictions:
- If the
Model
becomes complicated, then it becomes difficult to determine when to use the notifyListeners()
method, and when not, to avoid unnecessary interface updates. - The API provided by the
Model
does not, in general, accurately describe the asynchronous nature of the application interface.
Considering all this, if the state of your application is not easy to manage - I do not recommend using the data approach. I just do not believe that he is capable of productively ensuring the growth and complexity of applications.
Powerful Solution - BLoC
This pattern was coined by Google and used in the same place. He will help us achieve the following goals:
- Separation of mapping logic from business logic
- Using asynchronous nature to display the interface
- Ability to reuse in different Dart applications, such as Flutter or AngularDart
The idea of this approach is very simple:
- BLoC uses
Sink<T>
Api to describe asynchronously entering our data components. - BLoC uses
Stream<T>
Api to describe the data asynchronously returned by our data components. - Finally, we can use the
StreamBuilder
widget to manage data streams, without any effort on our part to subscribe to data updates and redraw widgets.
Google has good examples of using this condition management pattern, because it is widely used and highly recommended by the company.
I myself highly recommend using this approach to manage the local state, but it is suitable even for managing the global state. However, in the latter case, you will encounter a problem - where and how to implement BLoC correctly, so that different components can access it, and Redux comes on the scene.
Redux and BLoC - the perfect mix for me
One of the goals that I described at the beginning of the article was to search for something widely used and predictable, and this Redux is a pattern and a set of tools that together help us manage the global state. It has three basic principles at its core:
The only source of truth is that the entire `
state
your application is stored in a tree object in the only store `
store
- The state is read-only — the only way to change the state is to call a special action object that describes what should happen to the state.
- Changes are made using pure functions - to determine what changes in the state you write a clean function `
reducer
, which should not cause any side effects `Link to sample code`
Link to the original post where the image is takenThis approach to state management is widely accepted by web developers, and its appearance on mobile devices will help to get the benefits of web and mobile-application developers.
Brian Egan is developing both the original
Redux and
flutter_redux , and he also created a terrific
Todo application , in which he applied many architectural patterns, including Redux.
Considering all the qualities of Redux, I strongly advise using it to manage the global state, but you must be sure that you do not use it to manage the local state if you want to scale your application.
Last words
This article is not completely correct or incorrect decision. To decide on what approach to use in your project, you need to determine your needs. For me and my goals, the combination of Redux and BLoC allows my projects to grow quickly and safely, and also facilitates the entry of third-party developers into these projects, thanks to accessible and understandable tools. However, not everyone has the same needs and over time, you can find both problems in the current tools and even better solutions. It is very important to always remain curious, learn and think about whether this or that tool suits you.