T his article discusses State Management and how its handled in Flutter. We will cover SetState() , BLoC Architecture , Streams and Inherited Widget and get a general idea about their inner workings. I’ll list out the limitations that you may face and the ways in which BLoC architecture is superior. I hope you have a good time reading. so, let’s begin.
Flutter is a world of widgets. From a simple Container to a Button or any component you make is a widget. Widgets are the basic building blocks that can be reused at a later time.
When it comes to widgets, they can be classified into either Stateless or Stateful widgets. As the names suggest, Stateless widget have no internal state which means once built, can never be modified until and unless they’re initialized again. On the other hand, Stateful widgets are dynamic and have a state, which means that they can be modified easily throughout their lifecycle without reinitiation.
You must be wondering what is a State and how they are related in widget rendering??
According to Flutter, State is information that can be read synchronously when the widget is built and might change during the lifetime of the widget. State objects that are created by the framework. In order to change your widget, you need to update the state object which can be done using setState() function available for Stateful widgets. setState sets properties of state object which in turn triggers the update to the UI.
But this technique has its own drawbacks. Why can’t we entirely depend on setState function?
Parent to Child Rendering
In a typical widget elementary tree, once setState is triggered from Parent, it renders all its children, their sub- children and so on. It causes unnecessary rendering of those children that have no state change to update, or in simpler words, you can’t specifically render a particular child or children.
Child to Child Rendering
In a typical widget tree, when two children of a parent are not in the same class as of the parent, rendering one child from another becomes impossible until and unless you involve the parent for the same. You either have to call a setState() from parent which in turn renders both children or pass a call-back function from one child to another child via the Parent.
In order to overcome these limitations and provide a MVC architect to your app, there are different State management techniques available in Flutter. Some of the common approaches are BLoC Architecture, Scoped Model, Redux. But the latter two, being Scoped Model and Redux have their own limitations in terms of boilerPlate, Scope and data rendering.
In order to overcome these limitations, BLoC Architecture was introduced.
BLoC Architecture is a business logic component that separates the business logic of your app from the UI of the app via the use of Streams, thus providing MVVM architecture support to your app. Since this is not a package but a logic, it provides freedom to the developer to architect their app according to their need.
This architecture was developed by Google developers Paolo Soares and Cong Hui and it was announced for the first time at 2018 Dart Conference.
As I mentioned earlier, BLoC Architecture is totally based on Streams and it is powered by Inherited Widgets which we will discuss later.
What are Streams?
Streams are sequences of asynchronous events. To understand this better, let’s think of a pipe containing some liquid where adding one color from one end will update the color of whole liquid. The end from which we add color is called a ‘Sink’ and the end from which we visualise these change is called a ‘Stream’. Whereas, StreamBuilder acts as an observable eye which keeps on listening for these and updates the screen color accordingly.
BLoC works like the same in Flutter. In order update the widget at run time we make these properties of the widget as a Stream which will change in run time using StreamController . These properties can be anything from colour, border, height, width etc. After a Stream is created, it can be easily modified and listened for via two properties exposed by Stream i.e sink and stream.
In order to update our widget with the change in stream, we wrap our widget in
StreamBuilder widget. StreamBuilder keeps listening to change in stream it is subscribed to and on any change, it re-renders the widget accordingly.
But we have another constraint to handle here. Currently, our two child widgets i.e
RaisedButton are in the same class as that of the parent. So, they can easily access the model instance created in parent class.
But think of a situation when these widgets are not in the same class as of their parent but are separated to two different classes. In order to listen or update stream in such a condition, we must provide our model instance created at parent class to these child widgets.
One of the ways to achieve it is by passing this model instance from parent to the needy child widget. But think of a situation when there is another intermediate class between them which causes unnecessary passing of instance via this intermediate parent that has no use of it apart from passing it to its child and in the case this tree is very deep and it becomes very hard to manage the passing of stream object.
Second way is to define them as a Global Singleton but there is no class destructor in Dart and it will remain alive until your app remains alive.
In order to provide a solution for this situation, Flutter provides a special widget called Inherited Widget . This widget is specially designed to hold data and to provide it throughout the widget tree, irrespective of its depth. So, in our case we create a
BlocProvide for our model, extended to
InheritedWidget which holds the instance of our BLoC model .
This is a one-time code set up. For the each BLoC model we make, we just have to extend the
BlocBase in our BLoC model, like we do here for our
After extending our BLoC model to
BlocBase , we need to wrap our parent widget with our
BlocProvider Widget and provide the instance of our model to
bloc field of this widget.
Once this is done, our needy child widget can easily access the instance of our model by calling
BlocProvider.of(context) method at any level and easily listen and modify the Stream.
and this is the final product!:clap::clap:
Please refer to the following GitHub link for the complete code
Contribute to jaiswalshubham84/bloc_demonstration development by creating an account on GitHub. github.com
Although there are other state management packages available in the market, I particularly like the BLoC Architecture because of its simplicity and freedom to use it accordingly. Apart from its support to reactive programming and MVVM architecture, it also allows to reuse your business logic across different Dart platforms like Angular Dart.
Finally, here I rest my case. :grin:
This article was all about my experience in Flutter. Please share the challenges you faced in State Management in Flutter and also your opinion on BLoC and how you think it compares to other State Management packages.
Thank you for reading this article!
Please feel free to share your feedback below and let me know if you found this helpful! Please :clap: if you liked this article.