Flutter BLoC Pattern for Dummies Like Me
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:
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:
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
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:
State-out. Whatever computations or logical operations that happen inside a BLoC, it should be delivered to the UI components through a
In using the
flutter_bloc package, everything happens in the
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.
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
This functions exactly the same as the
BlocProvider just with the capability to supply multiple BLoCs at once instead of chaining
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
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
The dispatch function
To actually input an
Event to a BLoC, use the
dispatch function. Simple as that.
And that’s it!
- Wherever widget the BLoC is instantiated, make sure that it is a
StatefulWidgetbecause properly disposing BLoCs is a must. Simply call
disposeon 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
BlocDelegateto 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.
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!