bloc icon indicating copy to clipboard operation
bloc copied to clipboard

feat: method for safe emission of new states

Open tomassasovsky opened this issue 2 years ago • 3 comments

Description In personal and work projects, we use a lot a method that we basically copy-paste for every Bloc/Cubit. This is it:

  void safeEmit(State state) {
    if (isClosed) return;
    emit(state);
  }

This avoids new states to be emitted after closing the Bloc, so the Bad state error doesn't get thrown.

Desired Solution Ideally, add the safeEmit function to the BlocBase class.

tomassasovsky avatar Jun 20 '22 18:06 tomassasovsky

It's complicated for BLoC since emit is actually Emitter callable class.

You could just use extensions methods:

extension EmitterX<T> on Emitter<T> {
  void safe(State state) {
    if (isClosed) return;
    emit(state);
  }
}

Usage:

on<Event>((event, emit) => emit.safe(MyState());

For cubit:

extension CubitX<T> on Cubit<T> {
  void safeEmit(State state) {
    if (isClosed) return;
    emit(state);
  }
}

Usage:

safeEmit(MyState());

For Cubit you also could use mixins.

AlexanderFarkas avatar Jun 23 '22 11:06 AlexanderFarkas

This is indeed a common case people talk about often. Similarly, in Flutter, you can see navigator.pop() and navigator.canPop() or BuildContext and its context.mounted property.

It is hard to say whether some way of safeEmit or integrating it into the emit method is conceptually the right way we should do it.

While it makes sense, it can hide potential errors, like making navigator.safePop() etc. The issue is that especially after an async task, you cannot be sure about the state of bloc's stream. (similarly, as you cannot be sure whether a widget is mounted or not)

We could suppress it directly in the emit method by checking each time, but that hides all the issues. And I do not think it is the best thing to do as part of this main library. You can always override it by using extensions as stated above in your project.

tenhobi avatar Mar 11 '23 18:03 tenhobi

It's complicated for BLoC since emit is actually Emitter callable class.

You could just use extensions methods:

extension EmitterX<T> on Emitter<T> {
  void safe(State state) {
    if (isClosed) return;
    emit(state);
  }
}

Usage:

on<Event>((event, emit) => emit.safe(MyState());

The isClosed property is from Bloc, not from Emitter

nogicoder avatar Oct 24 '23 08:10 nogicoder