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?
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?
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.
Cubit is perfectly suitable to any app scale. None of those is better than the other.
You have to chose between traceability and event sharing vs boiler plate.
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
}
That alone gives you traceability because you know which event triggered the changes just by looking at the logs. You see eventA happened then eventB. In practice though, 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. So I'd say in that area Cubit wins, because the extra traceability is often not worth the boiler plate cost.
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 shared between multiple blocs that need to react to it. If action must be shared between blocs (example reset data on logout), then blocs can be handy in that area. However it might be a better architecture model not to mix one bloc with another, or it might not be, it depends. It's a judgment call here.
I'd say Bloc wins in the event sharing aspect. I'll also say that it's debatable whether event sharing is a good idea or not.
The Cubit is suitable for simple State management where you just have one kind of event to bind to the state. While Bloc is 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))
}
}
To implement above code with Cubit we will need switch cases (boilerplate)
Bloc force you to map each event to a separate function which is good when you have a complex state.
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.