When your state objects become complex, rebuilding the entire UI on every state change can hurt performance. BlocSelector solves this by allowing you to listen to only the specific parts of the state that your widget cares about. It rebuilds only when the selected value changes, making your app faster and more efficient.
What is BlocSelector?
BlocSelector<Bloc, State, Selected> is a Flutter widget that rebuilds only when the selected value changes. It takes a selector function that extracts a part of the state, and a builder that receives the selected value. Unlike BlocBuilder, which rebuilds on any state change, BlocSelector gives you fine‑grained control over rebuilds.
When to Use BlocSelector
- Large state objects – When state has many fields and you only need a few.
- Frequent state changes – To avoid rebuilding expensive widgets.
- Performance‑critical screens – Lists, animations, or complex forms.
- Independent UI components – When widgets depend on different parts of the same state.
Basic Usage
Define a selector function that returns the part of the state you need. The builder receives the selected value and returns a widget. The widget rebuilds only when the selected value changes (based on == equality).
In this example, the Text widget rebuilds only when the user's name changes, not when other fields like email or age change.
Comparing BlocSelector with Other Approaches
You can achieve similar behaviour using context.select inside a BlocBuilder or a custom widget, but BlocSelector is the dedicated widget for this purpose and often more readable.
Real-World Example
Consider a Dashboard screen with a complex DashboardState containing user profile, notifications, and settings. Different widgets need different parts of the state.
BlocSelector with Complex Selections
The selector can return any type, including custom objects. However, ensure those objects are immutable and implement equality (Equatable) to avoid false positives.
Performance Benefits
- Fewer rebuilds – Only widgets that depend on changed data rebuild.
- Better frame rates – Reduces layout and painting work, especially on low‑end devices.
- Cleaner separation – Each widget explicitly declares its dependencies.
- Easier debugging – You can trace exactly why a widget rebuilt by checking the selected value.
Best Practices
- Use
BlocSelectorfor widgets that depend on a small part of the state – Avoid passing the entire state to a widget that only needs one field. - Combine with
Equatable– Always extendEquatableon your state classes to enable correct equality checks. - Keep selectors simple – If a selector becomes complex, move it to a method or a getter on the state class.
- Use
BlocSelectorinsideListView.builderitems – Prevents rebuilding the entire list when one item's data changes. - Prefer
BlocSelectorover manualcontext.selectinsidebuild– It's more declarative and easier to read.
Common Mistakes
- ❌ Not using
Equatable– The selector's return value will be compared by reference, causing unnecessary rebuilds even when data is the same. - ❌ Selecting a mutable object – If the selected object is mutated (not replaced), equality won't detect changes. Always use immutable state.
- ❌ Selecting the entire state – That defeats the purpose; use
BlocBuilderinstead if you need the whole state. - ❌ Over‑optimizing prematurely – For small states,
BlocBuilderis fine; useBlocSelectorwhen performance issues appear. - ❌ Forgetting to include the selected value in the builder – The builder receives only the selected value, not the full state.
What's Next?
Now that you know how to optimise rebuilds, explore other Bloc widgets like BlocListener for side effects and BlocConsumer for combined builder and listener patterns.
Next, explore BlocListener and BlocConsumer.