Cubit: emit and the state stream
Cubit extends BlocBase and changes state through method calls. The initial state is passed to the constructor, and methods publish new states with emit().
The core rules:
state— synchronous access to the current state.emit(newState)— publishes a new state. It is called only from inside the cubit; changing state from outside is impossible, and that restriction is deliberate.- A warning from the official docs: both blocs and cubits ignore duplicate states — when
state == nextState, no state change occurs. close()— the end of the cubit's life;BlocProvidercalls it automatically.
dart
class WeatherState {
const WeatherState({
this.isLoading = false,
this.weather,
this.error,
});
final bool isLoading;
final Weather? weather;
final String? error;
WeatherState copyWith({bool? isLoading, Weather? weather, String? error}) =>
WeatherState(
isLoading: isLoading ?? this.isLoading,
weather: weather ?? this.weather,
error: error,
);
}
class WeatherCubit extends Cubit<WeatherState> {
WeatherCubit(this._repository) : super(const WeatherState());
final WeatherRepository _repository;
Future<void> load(String city) async {
emit(state.copyWith(isLoading: true, error: null));
try {
final weather = await _repository.fetch(city);
emit(state.copyWith(isLoading: false, weather: weather));
} catch (error) {
emit(state.copyWith(isLoading: false, error: '$error'));
}
}
}A cubit doing async work: loading, result and error.
The duplicate-state rule cuts both ways in practice. The benefit: re-emitting the same value does not rebuild the UI needlessly. The trap: if the state class does not implement == properly (no Equatable, so every copyWith is a new object), every emit counts as "new" and the filter never fires; conversely, if you mutate a field in place and emit the same object, == sees no difference and the UI never updates.
| Cubit | Bloc |
|---|---|
| State changes through a method call | State changes through an event |
| Less code: no event classes | More code, but every change has a name |
| What changed the state is visible at the call site | `onTransition` records the whole chain (state → event → state) |
| Reactive operators (debounce, throttle) are hand-written | Built-in support through `EventTransformer` |
📚 Sources and documentation
- Bloc concepts: Cubitofficialbloclibrary.dev
The official source for emit, the duplicate-state rule and the Cubit/Bloc comparison.
- package:blocofficialpub.dev
- Why Bloc?officialbloclibrary.dev