home / skills / hoangnguyen0403 / agent-skills-standard / bloc-state-management

bloc-state-management skill

/skills/flutter/bloc-state-management

This skill helps you implement predictable Flutter BLoC state management with freezed and equatable, guiding events, states, and UI integration.

npx playbooks add skill hoangnguyen0403/agent-skills-standard --skill bloc-state-management

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
1.7 KB
---
name: Flutter BLoC State Management
description: Standards for predictable state management using flutter_bloc, freezed, and equatable.
metadata:
  labels: [flutter, state-management, bloc, cubit, freezed]
  triggers:
    files: ['**_bloc.dart', '**_cubit.dart', '**_state.dart', '**_event.dart']
    keywords: [BlocProvider, BlocBuilder, BlocListener, Cubit, Emitter]
---

# BLoC State Management

## **Priority: P0 (CRITICAL)**

**You are a 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<Event>`.
4.  **Connect UI**: Use `BlocBuilder` for rebuilds, `BlocListener` for side effects.

## Implementation Guidelines

- **States & Events**: Use `@freezed` for union types.
- **Error Handling**: Emit `Failure` states; never throw exceptions in `on<Event>`.
- **Async Data**: Use `emit.forEach` for streams.
- **Concurrency**: Use `transformer: restartable()` for search/typeahead.

## 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.

## References

- [Templates](references/bloc_templates.md)

Overview

This skill codifies standards for predictable, testable Flutter state management using flutter_bloc, freezed, and equatable. It provides a clear workflow for designing events, states, and BLoC logic to keep UI layers thin and side effects isolated. The goal is robust, maintainable flows that are easy to test and reason about.

How this skill works

Start by modeling user interactions and outcomes as @freezed union types for Events and States. Implement a BLoC that maps Events to States using on<Event> handlers, async emit patterns, and transformers for concurrency. Connect the UI with BlocBuilder for rendering and BlocListener for navigation and other side effects, while ensuring errors become Failure states rather than thrown exceptions.

When to use it

  • When you need predictable, testable state flows across screens or features.
  • When UI must reflect asynchronous data sources such as APIs or streams.
  • When multiple UI components need to react to the same business logic.
  • When you want to keep navigation and one‑off effects out of build methods.
  • When you need easy unit and blocTest coverage for state transitions.

Best practices

  • Define all Events and States with @freezed to get exhaustive unions and pattern matching.
  • Emit errors as Failure states; avoid throwing inside on<Event> handlers.
  • Use await or emit.forEach for async work; avoid .then() chains that complicate tests.
  • Keep BlocBuilder pure (rendering only); place navigation and Snackbars in BlocListener.
  • Use transformer: restartable() (or debounce) for search/typeahead to manage concurrency.

Example use cases

  • A search screen using restartable transformer to handle rapid query changes and emit Loading/Data/Error states.
  • An authentication flow with Initial, Loading, Authenticated, and Unauthenticated states and tests covering all transitions.
  • A realtime feed implemented with emit.forEach(stream) to map incoming items to Data states while preserving testability.
  • A form submission flow where validation and API calls are handled in the BLoC and UI shows states via BlocBuilder and Snackbars via BlocListener.

FAQ

How should I handle side effects like navigation?

Emit states that represent outcomes and handle navigation or Snackbars in BlocListener rather than in BlocBuilder or the BLoC emitting direct navigator calls.

What testing approach is required?

Use blocTest to cover all state transitions, verify the initial state, and mock async dependencies so tests assert emitted states only.