Flutter BLoC Pattern for Dummies Like Me

Photo by Rick Mason on Unsplash

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:

  • 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 call dispose 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!