--- name: flutter-bloc-state-management description: Implement BLoC/Cubit state, events, transitions, and async concurrency in Flutter. Use for BLoC/Cubit feature logic, debounced/cancellable events, state rendering, or bloc tests—not generic widget-only work. metadata: triggers: files: - '**_bloc.dart' - '**_cubit.dart' - '**_state.dart' - '**_event.dart' keywords: - BlocProvider - BlocBuilder - BlocListener - Cubit - Emitter upstream: - name: bloc source: github repo: felangel/bloc pinned: "9.0.0" tag_pattern: "^bloc-v(\\d+\\.\\d+\\.\\d+)$" reviewed: "2026-07-09" --- # BLoC State Management ## **Priority: P0 (CRITICAL)** **Role**: Flutter State Management Expert. Design predictable, testable state flows. ## State Design Workflow 1. **Define Events**: What happens? (UserTap, ApiSuccess). Use `@freezed`. 2. **Define States**: What needs to show? (Initial, Loading, Data, Error). 3. **Implement BLoC**: Map Events to States using `on`. 4. **Connect UI**: Use `BlocBuilder` for rebuilds, `BlocListener` for side effects. ## Implementation Guidelines - **States & Events**: Use **@freezed** for union types (e.g., `Initial`, `Loading`, `Success`, `Failure` states). - **Error Handling**: Emit `Failure` states for UI-critical errors. For silent/background events, either let exceptions propagate naturally to global `onError` interceptor (e.g., in `AppBlocObserver`), or catch and call `addError(e, st)` without emitting error state. - **Async Data**: Use **emit.forEach** for streams or **await** with `emit` call. - **Concurrency**: Use **transformer: restartable()** from `bloc_concurrency` for search/typeahead to debounce and cancel previous requests. - **UI Connectivity**: Use **BlocBuilder** for UI rebuilds (e.g., loading spinner, data list, error message) and **BlocListener** for side effects (navigation, snackbars). - **Testing**: Use **blocTest** for ALL states and verify sequence of emitted states. ## Verification Checklist (Mandatory) - [ ] **Initial State**: Defined and tested? - [ ] **Test Coverage**: `blocTest` used for ALL states? - [ ] **UI Logic**: No complex calculation in `BlocBuilder`? - [ ] **Side Effects**: Navigation/Snackbars in `BlocListener` (NOT Builder)? ## Anti-Patterns - **No .then()**: Use `await` or `emit.forEach()` to emit. - **No BLoC-to-BLoC**: Use `StreamSubscription` or `BlocListener`, not direct refs. - **No Logic in Builder**: Move valid logic to BLoC. - **No BlocBuilder without buildWhen**: Heavy subtrees must declare `buildWhen` predicate to prevent unnecessary rebuilds. ## Verification - [ ] Every BLoC has `blocTest` covering Initial → Loading → Success and Initial → Loading → Failure. - [ ] Side effects (navigation, snackbars) use `BlocListener`, not `BlocBuilder`. - [ ] Heavy `BlocBuilder` widgets declare `buildWhen`. - [ ] `flutter test` passes. ## References - [Templates](references/bloc_templates.md) ## Event-handler correction - `emit()` is not a Future: **Remove** `.then()` from it, use `await` for asynchronous work, and register the event with an `on` handler. ## Canonical response anchors When this skill applies, preserve the following domain terminology or equivalent concrete examples in the answer when relevant: - Remove