side_effect_cubit 2.0.0 copy "side_effect_cubit: ^2.0.0" to clipboard
side_effect_cubit: ^2.0.0 copied to clipboard

"An extension to the bloc state management library which serve an additional stream for events that should be consumed only once"

Side Effect Cubit #

An extension to the bloc state management library which serve an additional stream for events that should be consumed only once - as usual called one-time events.

Support test package: side_effect_cubit_test

Why Side Effects? #

In modern state management (like Bloc or Cubit), State represents the persistent UI data (e.g., "Loading", "Loaded with [Data]", "Error"). The UI rebuilds whenever the state changes.

However, some actions are one-time events that shouldn't persist or trigger a UI rebuild in the traditional sense. These are called Side Effects.

Examples include:

  • Navigating to a new screen.
  • Showing a SnackBar, Toast, or Dialog.
  • Playing a sound.
  • Logging an analytics event.

If you handle these as part of the State:

  1. Re-triggering issues: If the screen rebuilds (e.g., keyboard opens, rotation), the "Show Error" state might re-trigger the error dialog/snackbar again.
  2. Boilerplate: You often have to dispatch a "Reset" event immediately after consuming the state to prevent it from happening again.

Side Effect Cubit solves this by providing a separate stream specifically for these one-off actions, decoupling them from your persistent state.

Usage #

1. Adding to existing one #

For Bloc:

class FeatureBloc extends Bloc<FeatureEvent, FeatureState>
    with SideEffectBlocMixin<FeatureEvent, FeatureState, FeatureSideEffect> {
  FeatureBloc() : super(FeatureState.initial());
}

For Cubit:

class FeatureCubit extends Cubit<FeatureState>
    with SideEffectCubitMixin<FeatureState, FeatureSideEffect> {
  FeatureCubit() : super(FeatureState.initial());
}

2. Inherit #

For Bloc:

class FeatureBloc extends SideEffectBloc<FeatureEvent, FeatureState, FeatureSideEffect> {
  FeatureBloc() : super(FeatureState.initial());
}

For Cubit:

class FeatureCubit extends SideEffectCubit<FeatureState, FeatureSideEffect> {
  FeatureCubit() : super(FeatureState.initial());
}

Emit side effect #

class FeatureBloc extends SideEffectBloc<FeatureEvent, FeatureState, FeatureSideEffect> {
  FeatureBloc() : super(FeatureState.initial()) {        
    on<ItemClick>(
      (event, emit) {
        produceSideEffect(FeatureSideEffect.openItem(event.id));
      },
    );
  }
}
class FeatureCubit extends SideEffectCubit<FeatureState, FeatureSideEffect> {
  FeatureCubit() : super(FeatureState.initial());

  Future<void> openItem(int id) async {
    produceSideEffect(FeatureSideEffect.openItem(id));
  }
}

Listen side effect #

BlocSideEffectListener<FeatureBloc, FeatureSideEffect>(
  listener: (BuildContext context, FeatureSideEffect sideEffect) {
    sideEffect.when(
      goToNextScreen: () => Navigator.of(context).pushNamed("/second_screen"),
      showPopupError: (errMsg) {
        // ....
      }
    );
  },
  child: ...
)
BlocSideEffectConsumer<FeatureBloc, FeatureState, FeatureSideEffect>(
  sideEffectListener: (BuildContext context, FeatureSideEffect sideEffect) {
    // Handle side effects here
  },
  listenWhen: (previous, current) {
    // Return true/false to determine when to call listener
    return true; 
  },
  listener: (context, state) {
    // Regular Bloc listener
  },
  buildWhen: (previous, current) => true,
  builder: (BuildContext context, FeatureState state) {
    return ...
  }
)
2
likes
150
points
1.63k
downloads

Publisher

verified publishersontieu.dev

Weekly Downloads

"An extension to the bloc state management library which serve an additional stream for events that should be consumed only once"

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, flutter_bloc, provider

More

Packages that depend on side_effect_cubit