Flutter Bloc Package

Felix Angelov
Flutter Community
Published in
4 min readOct 8, 2018

⚠️ This article may be out of date. Please view the official up-to-date documentation at bloclibrary.dev.

After having worked with Flutter for a bit, I decided to create a package to help with something that I have used quite frequently: the BLoC pattern.

For those not familiar with the BLoC pattern, it is a design pattern which helps separate the presentation layer from the business logic. You learn more about it here.

While using the BLoC pattern can prove to be challenging due to the setup as well as an understanding of Streams and Reactive Programming, at it’s core a BLoC is pretty simple:

A BLoC takes a stream of events as input and transforms them into a stream of states as output.

High-Level BLoC Architecture

We can now use this powerful design pattern with the help of the bloc package.

This package abstracts reactive aspects of the pattern allowing developers to focus on converting events into states.

Let’s start by defining those terms…

Glossary

Events are the input to a Bloc. They are commonly UI events such as button presses. Events are dispatched and converted to States.

States are the output of a Bloc. Presentation components can listen to the stream of states and redraw portions of themselves based on the given state (see BlocBuilder for more details).

Transitions occur when an Event is dispatched after mapEventToState has been called but before the bloc’s state has been updated. A Transition consists of the currentState, the event which was dispatched, and the nextState.

Now that we understand events and states we can take a look at the Bloc API.

Bloc API

mapEventToState is a method that must be implemented when a class extends Bloc. The function takes the incoming event as an argument. mapEventToState is called whenever an event is dispatched by the presentation layer. mapEventToState must convert that event into a new state and return the new state in the form of a Stream which is consumed by the presentation layer.

dispatch is a method that takes an event and triggers mapEventToState. dispatch may be called from the presentation layer or from within the Bloc (see examples) and notifies the Bloc of a new event.

initialState is the state before any events have been processed (before mapEventToState has ever been called). initialState is an optional getter. If unimplemented, initialState will be null.

transform is a method that can be overridden to transform the Stream<Event> before mapEventToState is called. This allows for operations like distinct() and debounce() to be used.

onTransition is a method that can be overridden to handle whenever a Transition occurs. A Transition occurs when a new Event is dispatched and mapEventToState is called. onTransition is called before a bloc’s state has been updated. It is a great place to add bloc-specific logging/analytics.

Let’s create a counter bloc!

Counter Bloc Implementation

In order to create a Bloc, all we need to do is:

  • Define our events and states
  • Extend Bloc
  • Override initialState and mapEventToState.

In this case our events are CounterEvents and our states are integers.

Our CounterBloc converts CounterEvents to integers.

We can notify out CounterBloc of events by calling dispatch like so:

In order to observe state changes (Transitions) we can override onTransition.

Now every time we dispatch a CounterEvent our Bloc will respond with a new integer state and we will see a transition logged to the console.

Now let’s build a UI using Flutter and hook up the presentation layer to our CounterBloc using the flutter_bloc package.

The flutter_bloc package provides two widgets to make interacting with Blocs easy:

BlocBuilder

BlocBuilder is a Flutter widget which requires a Bloc and a builder function. BlocBuilder handles building a widget in response to new states. BlocBuilder is very similar to StreamBuilder but has a more simple API to reduce the amount of boilerplate code needed.

BlocProvider

BlocProvider is a Flutter widget which provides a bloc to its children via BlocProvider.of(context). It is used as a dependency injection (DI) widget so that a single instance of a bloc can be provided to multiple widgets within a subtree.

Now let’s build our Counter App!

Our App widget is a StatefulWidget which is responsible for creating and disposing a CounterBloc. It makes the CounterBloc available to the CounterPage widget using the BlocProvider widget we mentioned above.

Our CounterPage widget is a StatelessWidget which uses BlocBuilder to rebuild the UI in response to state changes from our CounterBloc.

At this point we have successfully separated our presentational layer from our business logic layer. Notice that the CounterPage widget knows nothing about what happens when a user taps the buttons. The widget simply tells the CounterBloc that the user has pressed either the increment or decrement button.

That’s all there is to it!

For more examples and detailed documentation check out the official bloc documentation.

If you like the bloc library, you can support me by ⭐️the repository, or 👏 for this story.

--

--