When I first learned about BLoC, I thought it was just about events and their resulting states. For example, press a button, trigger an event, and the UI updates based on the state. This straightforward approach worked for simple apps, but it began to fall apart when I had to manage more complex UIs.
Take a screen with multiple filters and a list that refreshes locally, for instance. There were no API calls involved, but the interaction between UI elements demanded more thoughtful state management. It quickly became clear that my understanding of Bloc wasn’t scalable for real-world apps.
When I discussed this with colleagues, I realized many had faced similar struggles early on. The issue wasn’t Bloc itself—it was how we were approaching state design.
So, how do you avoid these pitfalls? The answer lies in:
Designing states mindfully and recognizing patterns that naturally emerge from thoughtful state management.
The turning point for me was recognizing that BLoC is more than just an event-to-state pipeline. It’s a tool to manage state as a concept, helping you create a predictable, scalable, and maintainable application. But this requires a mindset shift.
You need to think about:
Let me break this down with an analogy: Think of the state as a piece of fabric in a tailor’s shop. Each time you update the fabric, you create a new shirt. In your app, every state transition is like swapping out that fabric—the UI reflects a completely new “shirt” every time.
Flutter’s core principle says it best:
The UI is a function of state.
Here’s where most developers hit roadblocks: How do you design states that avoids rework and scales easily when new features are added?
At Aubergine, we’ve adopted a simple but effective approach: Visualize the UI as a chain of snapshots. Each snapshot represents a specific state of the UI. By focusing on these snapshots, we ensure that our state design remains clear and purpose-driven.
This means every state change determines how your build() method updates the UI. Once you grasp this, you’ll start to see the state as the foundation of your app’s design, not just a technical detail.
Here are few key strategies we follow when designing BLoC states:
Sometimes, your BLoC may need to interact with other parts of the app, requiring its state to be accessible globally. In such cases, ensure you expose only the essential parts of the state. Keep the exposed states minimal and focused to maintain clarity and encapsulation, avoiding unnecessary details or sensitive information.
Example: Authentication
An authentication feature might need to be exposed:
Avoid overloading this BLoC with transient states like loading or errors; these can often be handled more effectively at the UI layer. By keeping states minimal and focused, you create a cleaner interface for interacting with the Bloc.
For features tied to UI events, design states that reflect each possible outcome.
Example: List with API Calls
Imagine an API call that fetches a list of items. The UI might need to handle:
In this case:
Separating transient and persistent states keeps your implementation clean and ensures the UI handles each state appropriately.
This strategy involves collating all dynamic state variables into a single state object. It’s particularly useful for complex UIs where multiple elements need to interact.
Example: List with Filters and Pagination
Let’s say you have:
By centralizing these dynamic variables into one state, you ensure the UI always reflects the latest, unified state of the app. This approach is also effective for multi-screen flows like onboarding, where you want to manage navigation and user progress cohesively.
While not a hard rule, we typically avoid mixing setState() with Bloc-managed states.
Why?
Instead, rely on Bloc’s state stream to manage changes. This keeps your code consistent and predictable, especially in larger applications.
By following these strategies, you’ll find that:
You can always use these strategies in combination as per your requirement. You don’t have to use one at a time.
BLoC aligns seamlessly with our core development principles, facilitating mindful state design and supporting scalability and maintainability.
Mindful state management with BLoC has profound benefits for cross-platform app development, enhancing consistency, code reuse, and overall quality.
BLoC isn’t just a state management tool—it’s a way of thinking about how your app evolves. By designing states with intention and focusing on UI outcomes, you can build apps that are not only scalable but also easier to maintain.
If you’ve struggled with BLoC in the past, ask yourself:
Try applying the snapshot approach in your next feature. And if you have a unique way of managing BLoC states, I’d love to hear about it in the comments. Let’s continue learning and improving together!
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Block quote
Ordered list
Unordered list
Bold text
Emphasis
Superscript
Subscript