Question #286EasyState ManagementImportant

what is the difference between bloc vs cubit ?

#bloc

Answer

Overview

Cubit is a simplified version of BLoC — both are from the

text
flutter_bloc
package. Cubit removes the event layer, making it simpler and less boilerplate for straightforward state changes.


BLoC — Event-Driven

BLoC requires: Events → Bloc → States

dart
// Events
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
class Reset extends CounterEvent {}

// BLoC
class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<Increment>((event, emit) => emit(state + 1));
    on<Decrement>((event, emit) => emit(state - 1));
    on<Reset>((event, emit) => emit(0));
  }
}

// Dispatch events
context.read<CounterBloc>().add(Increment());

Cubit — Method-Driven (No Events)

Cubit skips the event layer — you call methods directly:

dart
// Cubit — no events needed
class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  void increment() => emit(state + 1);
  void decrement() => emit(state - 1);
  void reset() => emit(0);
}

// Call methods directly
context.read<CounterCubit>().increment();

Key Differences

FeatureBLoCCubit
Events✅ Required❌ No events
BoilerplateHigh (events + states + bloc)Low (just methods + states)
Traceability✅ Full of event history❌ Less traceable
Complex async
text
on<Event>
handlers
✅ Methods with async
Event transformation
text
transformer
parameter
❌ Manual
Best forComplex flows, many triggersSimple state changes

Same Widget Code for Both

dart
// BlocBuilder works the same for both!
BlocBuilder<CounterBloc, int>(
  builder: (context, count) => Text('$count'),
)

BlocBuilder<CounterCubit, int>(
  builder: (context, count) => Text('$count'),
)

When to Use Which

Use CaseRecommendation
Counter, toggle, loading flagCubit
Simple CRUD listCubit
Login with multiple statesBLoC or Cubit
Complex checkout flow with 5+ event typesBLoC
Need event transformation (debounce, concurrency)BLoC
Background sync with multiple triggersBLoC

Real-World Example — Auth with Both

dart
// As Cubit
class AuthCubit extends Cubit<AuthState> {
  AuthCubit() : super(AuthInitial());

  Future<void> login(String email, String password) async {
    emit(AuthLoading());
    try {
      final user = await authRepo.signIn(email, password);
      emit(AuthSuccess(user));
    } catch (e) {
      emit(AuthFailure(e.toString()));
    }
  }
}

// As BLoC — same logic but with event types
class AuthBloc extends Bloc<AuthEvent, AuthState> {
  AuthBloc() : super(AuthInitial()) {
    on<LoginRequested>(_onLogin);
    on<LogoutRequested>(_onLogout);
    on<GoogleSignInRequested>(_onGoogleSignIn);
    // Easier to manage 3+ actions separately as events
  }
}

Rule of thumb: Start with Cubit. Migrate to BLoC if you need event transformation, concurrency control, or complex multi-trigger logic. Both share the same widget API — migration is easy.