BLoC Pattern: Separating UI from Business Logic

The BLoC pattern treats app state as a stream: events go in, states come out. Use it in Flutter for complex state like user auth or data fetching. The footgun is overusing it for simple UI state, which creates unnecessary boilerplate.
WHY IT EXISTS In declarative UI frameworks like Flutter, widgets rebuild whenever their state changes. For complex apps, managing this state directly within UI widgets leads to tangled code where business logic and presentation are mixed. This makes the app difficult to test, reason about, and maintain as it grows.
THE MENTAL MODEL Think of a BLoC as a black box that sits between your UI and your business logic. The UI sends events (like 'LoginButtonPressed') into the box. The BLoC processes these events, performs any necessary work (like calling an API), and emits new states (like 'Loading', 'Success', or 'Error'). The UI simply listens to this stream of states and rebuilds itself accordingly.
HOW IT WORKS A BLoC is a Dart class that manages a stream of states. The UI dispatches events to the BLoC to signify user actions or other triggers. The BLoC contains the business logic to handle these events, and upon processing, it outputs a new state. In Flutter, widgets like BlocBuilder and BlocListener subscribe to the BLoC's state stream and rebuild the UI only when a new state is emitted, ensuring a clean separation of concerns.
WHEN TO USE IT BLoC is ideal for managing complex state that is shared across multiple screens or involves asynchronous operations. Use it for features like user authentication flows, shopping carts, or fetching and paginating data for an infinite list. Its strict separation makes business logic easy to test independently of the UI.
WHEN NOT TO USE IT Avoid BLoC for simple, ephemeral state that is confined to a single widget. For example, managing the open/closed state of a dropdown menu or the text in a single form field is often better handled with a StatefulWidget and setState. The boilerplate of creating events, states, and the BLoC class is overkill for such trivial cases.
ONE CANONICAL EXAMPLE A login screen. The UI dispatches a LoginSubmitted event with an email and password. The AuthBloc receives this, emits an AuthLoading state, makes an API call, and then emits either an AuthSuccess state (triggering navigation to the home screen) or an AuthFailure state (displaying an error message). The UI code itself contains zero API logic; it only builds based on the current state from the BLoC.
Read the original → bloclibrary.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.