BLoC State Management
Priority: P0 (CRITICAL)
Role: Flutter State Management Expert. Design predictable, testable state flows.
State Design Workflow
- Define Events: What happens? (UserTap, ApiSuccess). Use
@freezed. - Define States: What needs to show? (Initial, Loading, Data, Error).
- Implement BLoC: Map Events to States using
on<Event>. - Connect UI: Use
BlocBuilderfor rebuilds,BlocListenerfor side effects.
Implementation Guidelines
- States & Events: Use @freezed for union types (e.g.,
Initial,Loading,Success,Failurestates). - Error Handling: Emit
Failurestates for UI-critical errors. For silent/background events, either let exceptions propagate naturally to globalonErrorinterceptor (e.g., inAppBlocObserver), or catch and calladdError(e, st)without emitting error state. - Async Data: Use emit.forEach for streams or await with
emitcall. - Concurrency: Use transformer: restartable() from
bloc_concurrencyfor 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:
blocTestused for ALL states? - [ ] UI Logic: No complex calculation in
BlocBuilder? - [ ] Side Effects: Navigation/Snackbars in
BlocListener(NOT Builder)?
Anti-Patterns
- No .then(): Use
awaitoremit.forEach()to emit. - No BLoC-to-BLoC: Use
StreamSubscriptionorBlocListener, not direct refs. - No Logic in Builder: Move valid logic to BLoC.
- No BlocBuilder without buildWhen: Heavy subtrees must declare
buildWhenpredicate to prevent unnecessary rebuilds.
Verification
- [ ] Every BLoC has
blocTestcovering Initial → Loading → Success and Initial → Loading → Failure. - [ ] Side effects (navigation, snackbars) use
BlocListener, notBlocBuilder. - [ ] Heavy
BlocBuilderwidgets declarebuildWhen. - [ ]
flutter testpasses.