Introduction
In BLoC, BlocBuilder and BlocListener provide powerful ways to react to state changes. By default, BlocBuilder rebuilds its child on every state emission, and BlocListener executes its listener on every emission. This can lead to unnecessary rebuilds or side effects. The buildWhen and listenWhen parameters give you fine‑grained control to filter which state changes trigger rebuilds or side effects, significantly improving performance and user experience.
Understanding buildWhen
buildWhen is a predicate function that determines whether BlocBuilder should rebuild its child. It receives the previous state and the current state and returns a bool. If true, the builder runs; if false, it skips the rebuild.
Understanding listenWhen
listenWhen works similarly for BlocListener. It decides whether the listener callback should be invoked. This is useful for side effects like showing a snackbar, navigating, or logging.
Real‑World Example: User Profile Screen
Consider a profile screen that displays user details and also shows a loading indicator. You might want to rebuild the name widget only when the name changes, but show a snackbar only on error.
Using BlocConsumer for Combined Control
BlocConsumer combines BlocBuilder and BlocListener in a single widget. You can provide separate buildWhen and listenWhen to independently control rebuilds and side effects.
Advanced Patterns
For even finer control, you can combine buildWhen with context.select (which listens to a single property). Both approaches achieve similar results; choose based on readability.
You can also implement debouncing inside listenWhen to prevent repeated side effects (e.g., showing the same error multiple times). However, it's simpler to use listenWhen to filter duplicates.
Best Practices
- Use
buildWhento prevent unnecessary rebuilds – Especially for widgets that depend only on part of the state. - Use
listenWhento avoid duplicate side effects – Show snackbars only once per error, navigate only on transition, etc. - Keep predicates simple – Complex logic inside
buildWhencan be hard to maintain; extract to a method if needed. - Combine with
Equatable– Makes state comparison easier and reduces errors. - Consider
context.selectfor simple cases – It can be cleaner than a separatebuildWhen. - Test your filters – Ensure
buildWhenandlistenWhenreturn the correct boolean in unit tests.
Common Mistakes
- ❌ Using
buildWhenthat always returnstrue– No benefit, adds clutter. ✅ Use only when necessary. - ❌ Forgetting to handle initial state in
listenWhen– May cause side effects on first state. ✅ Checkpreviousfor initial. - ❌ Over‑filtering – Miss important updates. ✅ Test thoroughly to ensure correct behavior.
- ❌ Mutating state inside
buildWhen– Should be pure; no side effects. ✅ Keep predicate read‑only.
Conclusion
buildWhen and listenWhen are essential tools for optimizing BLoC‑powered Flutter apps. By selectively controlling rebuilds and side effects, you improve performance, reduce noise, and create a smoother user experience. Always consider which part of the state actually matters for each UI component and side effect.