Bloc Pattern In Flutter || Part 3💙

Manage the blocks of your app with BLoC!

Abhishek Doshi
3 min readSep 12, 2021

State Management is one of the most important concepts in Flutter. It’s not mandatory to use any State Management techniques, but it is obviously advisable to follow and maintain a good architecture so that you can access your data in any layer of the widget tree!

BLoC is one such State Management technique that is handy and easy to understand. If you are a complete beginner for BLoC, feel free to check out my other 2 articles on BLoC!

Recently, Felix Angelov (the creator of BLoC) published a new and more simplified version of the package. This article is totally dedicated to the new version of BLoC. You can also check the entire conversation for the new changes on GitHub!
So the main idea of the new version was to replace mapEventToState with on<Event> . Let’s see how it works now! We will be converting the same Counter App using BLoC with the new version

The new version is backwards compatible and is now available in the latest version of flutter_bloc i.e. 7.3.0

We won’t be going deep into how BLoC works as I have already written 2 articles for the same purpose. The main aim of this article is to focus on the changes that are available in the new version.

Initially, in our bloc class, we had mapEventToState where we had to add lots of if-else-if conditions based on our events. Example of same:

Stream<CounterState> mapEventToState(CounterEvent event) async* {
if (event is InitialCounterEvent) {
yield CounterDataState(counter: 0);
} else if (event is IncrementCounterEvent) {
yield CounterDataState(counter: event.counter + 1);
} else if (event is DecrementCounterEvent) {
yield CounterDataState(counter: (event.counter - 1).toUnsigned(event.counter.bitLength));
} else if (event is ResetCounterEvent) {
yield CounterDataState(counter: 0);

However, in the newer version, the constructor is enough to do most of our work! A new method named on is being introduced which creates streams for each event and then emits the state (instead of yielding). It registers an event handler for an event of type E. There should only ever be one event handler per event type E. The on<Event> method has the following function definition:

void on<E extends CounterEvent>(FutureOr<void> Function(E, Emitter<CounterState>) handler, {Stream<CounterEvent> Function(Stream<CounterEvent>, Stream<CounterEvent> Function(CounterEvent))? transformer})

Breaking it down, in simple words, it takes a method that has 2 required parameters event and emitter !

So the above code has now become much cleaner and more short!

CounterBloc() : super(CounterDataState(counter: 0)) {
on<InitialCounterEvent>((event, emit) => emit(CounterDataState(counter: 0)));
on<IncrementCounterEvent>((event, emit) => emit(CounterDataState(counter: event.counter + 1)));
(event, emit) => emit(CounterDataState(counter: (event.counter - 1).toUnsigned(event.counter.bitLength))));
on<ResetCounterEvent>((event, emit) => emit(CounterDataState(counter: 0)));

The whole file with both codes will look as follows:

FYI, the code snippet
(event.counter-1).toUnsigned(event.counter.bitLength) will return value >0 only and hence it works as a checkmark for negative values and the decrement won’t go below 0!

You can check out the entire project for reference on GitHub!

Here’s the output of the project:

Hope you enjoyed this article!

If you loved it, you can Buy Me A Coffee!

Don’t forget to connect with me on:

Don’t stop, until you are breathing!💙
- Abhishek Doshi



Abhishek Doshi

Google Developer Expert — Dart, Flutter & Firebase 💙💛