In the Bloc pattern, events are the input that trigger state changes. They represent user actions, lifecycle events, or any external input that should cause the application state to evolve. This guide covers everything you need to know about defining, handling, and optimising events in Flutter Bloc.
What Are Bloc Events?
Events are plain Dart classes that describe what happened. They are dispatched to the Bloc, which then processes them and emits new states. Events are the only way to interact with a Bloc – the UI never modifies state directly.
Defining Events
While this works, it’s better to use Equatable for proper equality checks. Without it, Bloc may not know when two events are identical, leading to unnecessary handlers being called.
Handling Events
Inside your Bloc, you define event handlers using the on<Event> method. Each handler receives the event and an Emitter to emit new states.
Event Transformers
Event transformers allow you to control how events are processed. They are especially useful for handling concurrent events, debouncing, or throttling. The most common transformers come from the bloc_concurrency package.
Common transformers:
sequential()– processes events one after another (default)concurrent()– allows multiple events to be processed simultaneouslydroppable()– drops new events if a previous handler is still runningrestartable()– cancels the current handler and starts a new one
Advanced Event Patterns
Sometimes you want to dispatch multiple events in response to a single action. You can do this inside the handler using add().
Use the where method on the event stream to filter events based on conditions.
Testing Events
Use the bloc_test package to test that your Bloc reacts correctly to events.
Best Practices for Events
- Use descriptive names –
LoginSubmittedis better thanLoginEvent. - Make events immutable – Use
finalfields and Equatable. - Keep events small – Each event should represent one logical action.
- Avoid bloated events – Don't put UI logic or heavy data in events.
- Use transformers for async flows – Prevent race conditions and unnecessary calls.
- Document events – Explain what each event does, especially in larger projects.
Common Mistakes
- ❌ Using the same event for different actions – Leads to complex conditional logic inside handlers.
- ❌ Not using Equatable – Causes event equality issues and potential bugs.
- ❌ Handling side effects inside events – Side effects belong in the handler, not the event.
- ❌ Creating events that are too specific – e.g.,
IncrementByOneandIncrementByTwo– use a singleIncrementwith a parameter. - ❌ Forgetting to handle errors – Always catch exceptions and emit appropriate error states.
What's Next?
Now that you understand events, explore how to structure your app using Bloc architecture and how to test your blocs effectively.