Flutter BLoC Pattern for Dummies Like Me
This story is outdated as I made this before flutter_bloc
1.0 even came out, I’m not sure if I will have time to update this but the overall concepts discussed here should still help you understand the BLoC patter easier
Design patterns are a surefire way to make your projects scalable, maintainable and optimised. At Google I/O 2018, Google introduced the BLoC pattern. It took a bit of time for me to understand the concept totally and to be able to actually use it in one of my projects. To help my fellow developers out, I detailed below my process of integrating BLoCs in the applications that I develop. I hope sharing this can help other developers understand the pattern easily.
Of course, I had to go through a couple of tutorials and related blogs to able to share this information and I recommend you go through them first as this will be a high level description of my process. Here are some of the materials that I studied:
- https://www.youtube.com/watch?v=LeLrsnHeCZY
- https://medium.com/flutter-community/flutter-todos-tutorial-with-flutter-bloc-d9dd833f9df3
- https://www.youtube.com/watch?v=Un7eG5hHNPg
Now, let’s look at how I use the BLoC pattern.
Note: I have been using the flutter_bloc
and the bloc
by Felix Angelov to simplify the implementation of the design pattern but please make sure to read the references I listed above to understand the inner workings of the pattern.
Create a BLoC for every screen or page
Sometimes even just knowing where to start helps a lot and it could help your productivity snowball. Immediately, I create the lib/bloc
folder and a BLoC for each page. Each page of your application should have its own parent BLoC. If a page has complex children which you think should have its own BLoC, then create a separate BLoC for it and have the parent subscribe to the child’s state changes and handle it accordingly.
For example, if there is a ListView
widget in the screen and the contents of that list is based on data retrieved from the database, then surely that should have its own BLoC. If anything needs to update in the screen after loading data aside from the list, the screen’s parent BLoC can handle it with the help of subscriptions.
Tackle it by screen
Since there are tons of wire-framing and prototyping tools out there such as Adobe XD and Sketch, it’s now easier to have an overview of the screens of an application. What works for me is examining each screen and deciding which widgets need to keep track of a state, which, therefore, will need a BLoC.
It is also important to know if a widget will even need a BLoC. This design pattern could seem a bit overkill for simple tasks and the reason for that is — it is overkill. For this part, I think it is up to your preference. I like having everything in a BLoC but sometimes having it so is unreasonably complicated.
I like going about it this way because, sometimes, you would not know the functionalities of a screen one-hundred-percent until you implement it. Sure you can spend a considerable amount of time thinking and writing it out but there is always something to be added upon implementation.
Enumerate the events
Next is to know which events are happening within a screen or a widget that should cause a state change. As you know, state changes happen when an event is dispatched to a BLoC. So, list down the events in verb form like so:
FetchData
UpdateTab
GetUserId
AddToCart
Here is a sample from one of my projects. It contains events that happen to convo/conversation data objects. I have also made it a practice to use the Flutter equatable
package. As you can see, you can easily pass parameters to an Event
class if it is needed by the BLoC for its computations. Here in the FetchConvos
event class, the userId
is passed to fetch Convo
entities for a specified user.
Enumerate the states
What hindered me from using the BLoC pattern for so long is, I haven’t seen a simple practical example of its usage. I really did not know what to put inside the states. So, think of this, which variables or data will my application use at certain states. That is exactly what a State
should contain, and how will it contain them? Through properties, since a state is really just a simple class.
Listing down the events first makes it clearer which states should come out of the BLoC. For the example above, if I have the event FetchConvos
then my mind would immediately think that one of the states should be ConvosLoaded
or ConvosFetched
. I always keep this mindset so that I don’t have to worry about naming my events and my states accordingly. Also, I always make sure to have an initial state for each of my BLoC to help with instantiation.
Build the BLoC
From the name itself, Business Logic Component, the BLoC should be able to handle the business which may include, querying the insertion of data to database, retrieval of data from database, and computing numbers. What’s important to understand here is: Event
-in, State
-out. Whatever computations or logical operations that happen inside a BLoC, it should be delivered to the UI components through a State
.
In using the flutter_bloc
package, everything happens in the mapEventToState
function
As you can see it calls the _mapFetchConvosToState
function, it takes care of the logic part which is the retrieval of the list of Convo
objects and then yields the state ConvosLoaded
, with the list inside of it as its property.
Use the BLoC
Okay, everything that I created has just been for setting up a BLoC. So, how do you use it? With the help of the Flutter package, this is extremely simple. First, you make use of three widgets.
BlocProvider
From the name itself, it provides a BLoC to its children wherever it may be in the widget tree. Here is how it is used:
For example purposes, I just put a Container
as a child but imagine if this is a widget with a whole lot more child widgets, then all of those widgets will be able to access the states inside the BLoC through the BlocProvider
.
BlocProviderTree
This functions exactly the same as the BlocProvider
just with the capability to supply multiple BLoCs at once instead of chaining BlocProviders
.
BlocBuilder
This is basically a widget that rebuilds itself automatically whenever the BLoC provided does a state change. It takes bloc
as a parameter and a builder
function.
To refer back to the BLoC that was provided by a BlocProvider
or a BlocProviderTree
, the syntax BlocProvider.of<NameOfBlocClass>(context)
is used. Within the builder function is a state
variable which is a reference to the BLoC’s current active state, and it is up to the presentation layer to check whichever is state is active and present the UI components accordingly.
Now that everything is set up, what is left is to just trigger an Event
for the BLoC to output a State
.
The dispatch function
To actually input an Event
to a BLoC, use the dispatch
function. Simple as that.
And that’s it!
Some notes
- Wherever widget the BLoC is instantiated, make sure that it is a
StatefulWidget
because properly disposing BLoCs is a must. Simply calldispose
on a BLoC to clean it up. - I mentioned using a parent BLoC for each page to help child BLoCs communicate with each other through subscriptions, make sure to dispose properly of those subscriptions to improve app performance.
- It would be helpful to create a barrel file for each
- You can also take a look at
BlocDelegate
to help with debugging or just tailoring the behaviour of BLoCs to your needs.
For more info, take a look at the official Github of Bloc.
Conclusion
I know this process is not my own. A lot of developers probably has these exact steps or an even better one but just explaining it this way (even to myself) has really helped me understand the complicated BLoC pattern. Actually, this process is a lot similar to Felix Angelov’s tutorial, I just wanted to synthesize all of my learnings about it as I find a lot of people like me who really do understand the design pattern conceptually but has had trouble in actually implementing it. I know this is a just a high-level overview of implementing the BLoC pattern but I hope this will help simplify a lot of things for you.
If this article helped you a 👏 would be nice and possibly share this to help others too. This is my first ever blog post so I would love to hear your thoughts and suggestions!