Stream Transformers and Event Debouncing in BLoC
Apply concurrency transformers to throttle, debounce, and sequence incoming events.
Why Event Concurrency Matters
In flutter_bloc, every call to add(event) pushes an event into an internal stream. By default each event handler runs concurrently as events arrive. For most events that is fine, but some sources fire far too often:
- Search bars emit a
TextChangedevent on every keystroke. - Scroll listeners emit dozens of
ScrolledToBottomevents per second. - Buttons can be tapped rapidly, firing duplicate
SubmitPressedevents.
Firing a network request per keystroke wastes bandwidth and can show stale results. This lesson shows how to throttle, debounce, and sequence these events using stream transformers in BLoC.
The transformer Parameter
The modern on<Event> API accepts an optional transformer argument. A transformer is an EventTransformer<E> — a function that receives the incoming Stream<E> of events and a mapper, and returns a transformed stream.
By supplying a transformer you control how events of that type are processed: debounced, throttled, dropped, or run one-at-a-time. The signature is:
typedef EventTransformer<Event> = Stream<Event> Function(Stream<Event> events, EventMapper<Event> mapper);
You rarely write transformers by hand — the bloc_concurrency package provides the common ones.
// Registering a handler with a custom transformer
on<SearchTermChanged>(
_onSearchTermChanged,
transformer: (events, mapper) => events
.debounceTime(const Duration(milliseconds: 300))
.switchMap(mapper),
);All lessons in this course
- Events, States, and the Cubit-vs-Bloc Decision
- Stream Transformers and Event Debouncing in BLoC
- Persisting State with HydratedBloc
- Testing BLoCs with bloc_test and Mocktail