Skip to main content

Cubit

A Cubit is a simplified version of a Bloc from the flutter_bloc package. It eliminates the need for defining custom Event classes, allowing you to trigger state changes by directly calling methods (functions).


1. What is a Cubit?

While a standard Bloc takes Events as inputs and emits States as outputs, a Cubit takes Methods as inputs and emits States as outputs.

Key Differences

FeatureCubitBloc
InputMethods / FunctionsEvents
OutputStatesStates
ComplexityLow to MediumMedium to High
TraceabilitySimplerHigher (via Event transition logs)
Event BufferingNo (instant execution)Yes (using RxDart transformers)

2. Code Example: Counter Cubit

Here is a clean implementation of a Counter state manager using Cubit.

Step 1: Define the Cubit

import 'package:flutter_bloc/flutter_bloc.dart';

class CounterCubit extends Cubit<int> {
// Pass the initial state to the super constructor
CounterCubit() : super(0);

// Define methods to mutate state
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}

Step 2: Consume the Cubit in the UI

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class CounterPage extends StatelessWidget {
const CounterPage({super.key});


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Cubit Counter')),
body: BlocBuilder<CounterCubit, int>(
builder: (context, count) {
return Center(
child: Text(
'$count',
style: Theme.of(context).textTheme.headlineMedium,
),
);
},
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () => context.read<CounterCubit>().increment(),
child: const Icon(Icons.add),
),
const SizedBox(height: 8),
FloatingActionButton(
onPressed: () => context.read<CounterCubit>().decrement(),
child: const Icon(Icons.remove),
),
],
),
);
}
}

3. When to Use Cubit vs. Bloc

  • Use Cubit when:

    • The state transitions are simple (e.g. toggles, fetching lists, loading indicators).
    • You do not need to buffer, debounce, or throttle inputs.
    • You want to write less boilerplate.
  • Use Bloc when:

    • State changes are highly complex and depend on event histories.
    • You need advanced stream operators (e.g. debouncing search queries, delaying clicks, throttling events).
    • You require absolute traceability of every event dispatched in the app.