What is the difference between Cubit and Bloc?
Asked Answered
F

4

69

I am a bit confused about the new release of Bloc: 6.0.0, adding Cubit notion, is the bloc depreciated or we can use both of them?

Fatherhood answered 28/7, 2020 at 9:29 Comment(1)
Bloc vs Cubit: bloclibrary.dev/#/coreconcepts?id=cubit-vs-blocThreadfin
F
65

Cubit is a subset of the BLoC Pattern package that does not rely on events and instead uses methods to emit new states.

So, we can use Cubit for simple states, and as needed we can use the Bloc.

UPDATE : additional comparison

There are many advantages of choosing Cubit over Bloc. The two main benefits are:

Cubit is a subset of Bloc; so, it reduces complexity. Cubit eliminates the event classes. Cubit uses emit rather than yield to emit state. Since emit works synchronously, you can ensure that the state is updated in the next line.

more details: bloclibrary

Fatherhood answered 28/7, 2020 at 9:29 Comment(5)
what is the meaning of a complex state? in which situation we can't use Cubit, can You explain?Fetter
@AlirezaTaghizadeh, in my opinion, you can use only Cubit BUT as I mentioned, Cubit is a subset of Bloc (Bloc extends Cubit) so you can think of Cubit as a simplified Bloc which has less functionality. Blocs are more powerful than Cubits but Cubits are more simple. again, it depends on what you gonna build, Big app use BLOC (complex funcs), simple app use Cubit( less funcs )Fatherhood
No, it is not related to size of app, for example you can't use cubit for stream data for example for stream firestore, it is not related to size of app, for example for authentication it is better use cubit in each big and small applications.Fetter
@AlirezaTaghizadeh For ex: Cubit has no notion of events, things like debounce, switchMap, throttle, etc... will not be as easy to support with Cubit and you'd be better off using Bloc.Fatherhood
thanks to @AlirezaTaghizadeh, now I have a faith for what condition to use either event in bloc or cubit.Infuscate
B
60

Cubit is perfectly suitable to any app scale and anyone saying one scales better than the other is ill-informed. Software architecture is rarely about absolutes, rather it is about pros and cons, and more often than not people claiming you should use X don't really understand the implications.

Bloc is essentially event driven architecture while cubit is vanilla code. This has the same implications that any event driven architecture has.

In short: Event driven or not

// this is normal / vanilla code, like cubits

myFuction();  // i'm just calling my function here, nothing magical going on

myFunction() {
  print('running my function');
}

// this is event driven, like blocs

eventEmitter.emit(SomeEvent()); // emitting an event, i don't know if it will be handled.

on(SomeEvent).exectute(myFunction);
// somewhere else in your code base...
on(SomeEvent).exectute(myAnalyticsFunction);


myFunction() {
  print('my function');
}

myAnalyticsFunction() {
  print('my analytics function');
}

The code above demonstrate the difference between vanilla execution vs an event driven one. As you can see event driven architectures comes with its own drawbacks:

  • adds complexity
  • adds indirection, you do not call the function directly
  • you cannot add a breakpoint to flow through code !
  • you cannot know which handler will execute after an event is emitted just by looking at the source of emission (you have to do a search)
  • you don't know in which order an event will be processed

It adds the following advantage:

  • allow you to decouple the emitting site from the processing sites
  • allows you to add event handlers at will without changing the existing code.
  • allows you to easily add cross cutting concerns (logging, analytics..) by just subscribing to all events.

Any time you use an event driven architecture, you lose some of the benefits of traditional code and this should be used with care: when needed.

One advantage of event driven architectures is that events can be used by 0 or many handlers, the emitter does not care. The disadvantage is the indirection and extra boiler plate.

Bloc vs Cubit

Traceability

When you use a bloc you have a Transition that contains the event:

Transition {
  currentState: AuthenticationState.authenticated,
  event: LogoutRequested,
  nextState: AuthenticationState.unauthenticated
}

When you use cubit it does not

Transition {
  currentState: AuthenticationState.authenticated,
  nextState: AuthenticationState.unauthenticated
}

One advantage is that you gain some traceability because you know which event triggered the changes just by looking at the logs. You see eventA happened then a change of state happened.

In practice, for the cubit you can often infer traceability from the changes themselves without the "label", because there is not many action that can output this change.

One disadvantage is indirection cost which shouldn't be understated, you cannot put a debugger and follow the code here by definition.

Event sharing

In essence, emitting an Action/Event that is then mapped to call a function, is just like calling the function directly. The only fundamental change is when an action must be consumed by multiple consumers, blocs or others (example analytics). If an action must be shared between blocs (example reset data on logout), then blocs can be handy in that area. However there are other ways to achieve that without requiring your whole code base to use bloc...

Cross cutting concerns

One aspect where, I think, event driven architecture shine is when you have to add cross cutting concerns that you want to apply to a wide range of events. For instance if you want to pipe all events to google analytics and log them in two lines of code, this would be easily done if you already had bloc. However even this doesn't require you to go with bloc, it just require an event to be emitted at some point, which would be a better pattern.

Conclusion

If you ask yourself should I use bloc or cubit, go with cubit. Once you have a clearly defined reason to use an event emitter of some sort, you can add it.

Beale answered 8/8, 2021 at 10:6 Comment(2)
Very clear! Thank you.Shamikashamma
I followed the example in bloc readme for implementing login flow, and it uses bloc, I thought to myself why there is unnecessary code, I just need to login, it should be the simplest thing in any app. I will defiantly change it to cubit, then use cubit for the entire app, I don't need the event classes just to fetch some data from an API then display it (my only need for state management is for global app state of that data).Naylor
S
25

I don't agree with opinions that you can only use Cubit only for simple cases, or for small apps. I would even say that Cubit can handle pretty complex cases without the need to be converted into a Bloc.

The main advantage of Cubit is that it has less boilerplate code, and has a straightforward and synchronous way for emitting states (as there is no Event class, but a simple functions instead). In most cases you won't need a Bloc, so you can easily use Cubits if you don't have to transform your events. In those rare cases when you need to transform events, you can easily refactor Cubit into a Bloc, as both of them extends BlocBase class.

The main difference between Cubit and Bloc is that in Bloc you have Event class in addition to State. So, you are able to use EventTransformer function in order to manipulate your events. For example, you can add debounce or throttle to your event. Or even have some complicated event stream mapping. That's the main benefit of using a Bloc instead of a Cubit.

An example of using EventTransformer for debouncing event:

import 'package:stream_transform/stream_transform.dart';

EventTransformer<Event> _debounce<Event>(Duration duration) {
  return (events, mapper) => events.debounce(duration).switchMap(mapper);
}

Usage of the _debounce in event mapping:

class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
  const ExampleBloc()
      : super(const ExampleState()) {
    on<ExampleEvent>(
      _onExampleEvent,
      transformer: _debounce(Duration(seconds: 1)),
    );
  }
  ...
}

Basically, that's the core difference between Cubit and Bloc.

P.S. Usage of Blocs / Cubits in projects is also quite opinionated, and some teams might use Blocs only due to code consistency.

Schramke answered 17/8, 2022 at 13:23 Comment(1)
Agree 100% I think we should always start with cubit, and if event transformer are required, then add event and switch to bloc.Colicroot
H
8

My rule is to use Cubit for simple State management where you just have one kind of event to bind to the state. And use Bloc for complex state management where you can have many events to map to states.

For example let consider below Cubit

class SimpleCubit extends Cubit<SimpleState> {
  SimpleCubit () : super(InitialState());
  
  void updateState(String stateName){
    emit(NewState(stateName));
  }  

}

Let now have a look on Bloc

class SimpleBloc extends Bloc<SimpleEvent, SimpleState> {
  SimpleBloc() : super(InitialState()){
    on<SimpleEven1>(_handleEvent1);
    on<SimpleEven2>(_handleEvent2)
  }

  Future<void> _handleEvent1(SimpleEvent event, Emitter<SimpleState1> emit) async {
   // Put your code here
   emit(SimpleState1(event.args))
}

  Future<void> _handleEvent2(SimpleEvent event, Emitter<SimpleState2> emit) async {
   // Put your code here
   emit(SimpleState2(event.args))
}
  
}

Bloc forces you to map each event to a separate function which is good when you have a complex state. Although with some extra codes you can achieve the same with Cubit, I prefer Bloc in that given case.

Hunger answered 10/6, 2021 at 10:48 Comment(5)
You shouldn't ever name method returning void as 'get ..'Septennial
This answer doesnt make sense. What prevents us form using switch in a cubit?Watchband
Note that mapEventToState is deprecated. @Deprecated - Use on<Event> instead. Will be removed in v8.0.0Exordium
This is not a correct answer. Cubits can have multiple states and functions as blocs. So you could have an event "SimpleEvent1" and "SimpleEvent2" in bloc, but also having to different functions "doSomething1()" and "doSomething2()" in the cubit. Both can emit multiple states.Miliary
THIS IS STRAIGHT UP WRONG. Idk if cubit changed at some point, but this couldn't be more wrong. Cubits can have multiple states and functions.Swastika

© 2022 - 2024 — McMap. All rights reserved.