|
| 1 | +--- |
| 2 | +title: State Management (BLoC) |
| 3 | +description: An explanation of the BLoC pattern for state management in the mobile client. |
| 4 | +--- |
| 5 | +import { Aside } from '@astrojs/starlight/components'; |
| 6 | + |
| 7 | +The mobile client uses the **BLoC (Business Logic Component)** pattern for state management. This pattern helps to separate the presentation layer from the business logic, making the application more structured, testable, and maintainable. |
| 8 | + |
| 9 | +Every feature in the application that requires managing state has its own BLoC. |
| 10 | + |
| 11 | +### The Core Components of BLoC |
| 12 | + |
| 13 | +A BLoC is made up of three main parts: |
| 14 | + |
| 15 | +1. **Events**: Events are the inputs to a BLoC. They are dispatched from the UI in response to user interactions (e.g., a button press) or lifecycle events (e.g., the page loading). Events are defined as simple classes that extend a base `Event` class. |
| 16 | + |
| 17 | +2. **States**: States are the outputs of a BLoC. They represent a part of the application's state and are emitted by the BLoC in response to events. The UI listens to the stream of states and rebuilds itself to reflect the latest state. States are typically modeled as immutable classes. |
| 18 | + |
| 19 | +3. **BLoC**: The BLoC itself is the component that sits between the UI and the data layer. It receives events, processes them (often by interacting with a repository), and emits new states. |
| 20 | + |
| 21 | +### A Practical Example: `AccountBloc` |
| 22 | + |
| 23 | +Let's look at the `AccountBloc`, which manages the state for the user's account screen. |
| 24 | + |
| 25 | +- **Event**: When a user toggles following a topic, the UI dispatches an `AccountFollowTopicToggled` event, which contains the `Topic` object. |
| 26 | + |
| 27 | + ```dart title="lib/account/bloc/account_event.dart" |
| 28 | + class AccountFollowTopicToggled extends AccountEvent { |
| 29 | + const AccountFollowTopicToggled({required this.topic}); |
| 30 | + final Topic topic; |
| 31 | + } |
| 32 | + ``` |
| 33 | + |
| 34 | +- **BLoC Logic**: The `AccountBloc` listens for this event. In its event handler, it updates the user's preferences by calling the `_userContentPreferencesRepository` and then emits a new state. |
| 35 | + |
| 36 | + ```dart title="lib/account/bloc/account_bloc.dart" |
| 37 | + on<AccountFollowTopicToggled>(_onAccountFollowTopicToggled); |
| 38 | +
|
| 39 | + Future<void> _onAccountFollowTopicToggled( |
| 40 | + AccountFollowTopicToggled event, |
| 41 | + Emitter<AccountState> emit, |
| 42 | + ) async { |
| 43 | + // ... logic to add/remove topic from preferences ... |
| 44 | + final updatedPrefs = // ... |
| 45 | + |
| 46 | + // Persist the change |
| 47 | + await _userContentPreferencesRepository.update(item: updatedPrefs); |
| 48 | +
|
| 49 | + // Emit the new state |
| 50 | + emit(state.copyWith(status: AccountStatus.success, preferences: updatedPrefs)); |
| 51 | + } |
| 52 | + ``` |
| 53 | + |
| 54 | +- **State**: The `AccountState` holds the current user's `UserContentPreferences`. When the BLoC emits a new state with the updated preferences, the UI rebuilds. |
| 55 | + |
| 56 | + ```dart title="lib/account/bloc/account_state.dart" |
| 57 | + class AccountState extends Equatable { |
| 58 | + const AccountState({ |
| 59 | + this.status = AccountStatus.initial, |
| 60 | + this.preferences, |
| 61 | + // ... |
| 62 | + }); |
| 63 | +
|
| 64 | + final AccountStatus status; |
| 65 | + final UserContentPreferences? preferences; |
| 66 | + // ... |
| 67 | + } |
| 68 | + ``` |
| 69 | + |
| 70 | +- **UI Integration**: The `FollowedTopicsListPage` uses a `BlocBuilder` to listen to the `AccountBloc`. When the state changes, it rebuilds the list of topics, and the UI reflects whether the topic is followed or not. |
| 71 | + |
| 72 | + ```dart title="lib/account/view/manage_followed_items/topics/followed_topics_list_page.dart" |
| 73 | + // ... |
| 74 | + body: BlocBuilder<AccountBloc, AccountState>( |
| 75 | + builder: (context, state) { |
| 76 | + // ... build UI based on state.preferences.followedTopics ... |
| 77 | + }, |
| 78 | + ), |
| 79 | + // ... |
| 80 | + ``` |
| 81 | + |
| 82 | +This unidirectional data flow—from UI event to BLoC to new UI state—is the foundation of state management in the application. |
0 commit comments