> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-skills-v5-temp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# BLoC & Data

> Configure data fetching with RequestBuilders, provide custom BLoC instances, and listen to state changes.

<Accordion title="AI Integration Quick Reference">
  | Field       | Value                                                                                                     |
  | ----------- | --------------------------------------------------------------------------------------------------------- |
  | Package     | `cometchat_chat_uikit`                                                                                    |
  | Import      | `import 'package:cometchat_chat_uikit/cometchat_chat_uikit.dart';`                                        |
  | Purpose     | Configure data fetching with RequestBuilders, provide custom BLoC instances, and listen to state changes. |
  | Key classes | `CometChatMessageList` · `CometChatConversations`                                                         |
  | Related     | [Message List](/ui-kit/flutter/message-list) · [Conversations](/ui-kit/flutter/conversations)             |
</Accordion>

Each component's BLoC manages data fetching, state transitions, and business logic. You can configure it via RequestBuilders, provide a custom BLoC instance, or extend the default one.

## Configuring Data Fetching with RequestBuilders

Use request builders to control what data the component fetches. Pass the builder instance — not the result of `.build()`.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      messagesRequestBuilder: MessagesRequestBuilder()
        ..uid = user.uid
        ..searchKeyword = 'hello'
        ..limit = 30,
    )
    ```
  </Tab>
</Tabs>

<Warning>
  The following parameters in `MessagesRequestBuilder` will always be altered inside the message list: UID, GUID, types, categories.
</Warning>

### Request Builder by Component

| Component                | Builder Property              | Builder Type                  |
| ------------------------ | ----------------------------- | ----------------------------- |
| `CometChatConversations` | `conversationsRequestBuilder` | `ConversationsRequestBuilder` |
| `CometChatUsers`         | `usersRequestBuilder`         | `UsersRequestBuilder`         |
| `CometChatGroups`        | `groupsRequestBuilder`        | `GroupsRequestBuilder`        |
| `CometChatGroupMembers`  | `groupMembersRequestBuilder`  | `GroupMembersRequestBuilder`  |
| `CometChatMessageList`   | `messagesRequestBuilder`      | `MessagesRequestBuilder`      |

## Providing a Custom BLoC

Each component accepts an optional BLoC parameter. Provide your own instance to override default behavior:

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    final myBloc = MessageListBloc(
      user: user,
      parentMessageId: null,
      types: MessageTemplateUtils.getAllMessageTypes(),
      categories: MessageTemplateUtils.getAllMessageCategories(),
    );

    CometChatMessageList(
      user: user,
      messageListBloc: myBloc,
    )
    ```
  </Tab>
</Tabs>

### BLoC Parameters by Component

| Component                  | BLoC Property         | BLoC Type             |
| -------------------------- | --------------------- | --------------------- |
| `CometChatConversations`   | `conversationsBloc`   | `ConversationsBloc`   |
| `CometChatMessageList`     | `messageListBloc`     | `MessageListBloc`     |
| `CometChatMessageComposer` | `messageComposerBloc` | `MessageComposerBloc` |

## Extending the Default BLoC

Extend the default BLoC class and override hooks to add custom behavior:

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    class CustomMessageListBloc extends MessageListBloc {
      CustomMessageListBloc({required User user})
          : super(user: user);

      @override
      void onItemAdded(BaseMessage item, List<BaseMessage> updatedList) {
        // Custom logic when a message is added
        debugPrint('Message added: ${item.id}');
        super.onItemAdded(item, updatedList);
      }

      @override
      void onItemRemoved(BaseMessage item, List<BaseMessage> updatedList) {
        // Custom logic when a message is removed
        super.onItemRemoved(item, updatedList);
      }

      @override
      void onItemUpdated(BaseMessage oldItem, BaseMessage newItem, List<BaseMessage> updatedList) {
        // Custom logic when a message is updated
        super.onItemUpdated(oldItem, newItem, updatedList);
      }
    }
    ```
  </Tab>
</Tabs>

### ListBase Hooks

All list-based BLoCs use the `ListBase` mixin with these override hooks:

| Hook                                           | Called When                      |
| ---------------------------------------------- | -------------------------------- |
| `onItemAdded(item, updatedList)`               | An item is added to the list     |
| `onItemRemoved(item, updatedList)`             | An item is removed from the list |
| `onItemUpdated(oldItem, newItem, updatedList)` | An item is updated in the list   |
| `onListCleared(previousList)`                  | The list is cleared              |
| `onListReplaced(previousList, newList)`        | The entire list is replaced      |

## Component-Specific BLoC Events

Each component's BLoC has its own events and methods. See the individual component docs for details:

* [Message List — BLoC Events & Methods](/ui-kit/flutter/message-list#advanced)
* [Conversations — BLoC Events](/ui-kit/flutter/conversations#advanced)
* [Users — BLoC Events](/ui-kit/flutter/users#advanced)
* [Groups — BLoC Events](/ui-kit/flutter/groups#advanced)
* [Group Members — BLoC Events](/ui-kit/flutter/group-members#advanced)

## Lifecycle Callbacks

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      onLoad: (messages) {
        debugPrint('Loaded ${messages.length} messages');
      },
      onEmpty: () {
        debugPrint('No messages found');
      },
      onError: (e) {
        debugPrint('Error: $e');
      },
    )
    ```
  </Tab>
</Tabs>

## Related

* [Message List](/ui-kit/flutter/message-list) — Full message list component reference.
* [Customization Overview](/ui-kit/flutter/customization-overview) — See all customization categories.

***

## Repository & Datasource Overrides

Both `CometChatConversations` and `CometChatMessageList` follow the same clean architecture stack. There are two override points:

```
Widget → BLoC → UseCase → Repository → DataSource (Remote + Local)
                  ↑               ↑
          override here    or here
```

### 1. Datasource Override

Implement the abstract datasource interfaces to swap the data layer entirely — e.g. a REST API instead of the CometChat SDK, or a persistent cache instead of in-memory.

#### Conversations

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    abstract class ConversationsRemoteDataSource {
      Future<List<Conversation>> getConversations({int limit, String? fromId});
      Future<Conversation> getConversation(String conversationId);
      Future<void> deleteConversation(String conversationWith, String conversationType);
      Future<void> markMessageAsRead(BaseMessage message);
      Future<Conversation> updateConversation(Conversation conversation);
    }

    abstract class ConversationsLocalDataSource {
      Future<void> cacheConversations(List<Conversation> conversations);
      Future<List<Conversation>> getCachedConversations();
      Future<void> cacheConversation(Conversation conversation);
      Future<Conversation?> getCachedConversation(String conversationId);
      Future<void> removeCachedConversation(String conversationId);
      Future<void> clearCache();
      Future<bool> hasCachedData();
    }
    ```
  </Tab>
</Tabs>

#### Message List

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    abstract class MessageListRemoteDataSource {
      Future<GetMessagesResult> getMessages({...});
      Future<List<BaseMessage>> fetchPreviousMessages({required MessagesRequest request});
      Future<List<BaseMessage>> fetchNextMessages({required MessagesRequest request});
      Future<void> markAsRead(BaseMessage message);
      Future<void> markAsDelivered(BaseMessage message);
      Future<User?> getLoggedInUser();
      Future<Conversation> getConversation({...});
      Future<Conversation> markMessageAsUnread(BaseMessage message);
    }

    abstract class MessageListLocalDataSource {
      Future<void> cacheMessages(String conversationId, List<BaseMessage> messages);
      Future<List<BaseMessage>> getCachedMessages(String conversationId);
      // ... cache CRUD methods
    }
    ```
  </Tab>
</Tabs>

***

### 2. Repository Override

The repository interfaces sit above the datasources. Override here to change business logic — caching strategy, error handling, retry logic — without touching the datasource layer.

#### Conversations

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    abstract class ConversationsRepository {
      Future<Result<List<Conversation>>> getConversations({int limit, String? fromId});
      Future<Result<Conversation>> getConversationById(String conversationId);
      Future<Result<void>> deleteConversation(String conversationId);
      Future<Result<Conversation>> updateConversation(Conversation conversation);
      Future<Result<User?>> getLoggedInUser();
      Future<Result<void>> markAsDelivered(BaseMessage message);
      Future<Result<Conversation>> getConversation({...});
    }
    ```
  </Tab>
</Tabs>

#### Message List

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    abstract class MessageListRepository {
      Future<Result<List<BaseMessage>>> getMessages({...});
      Future<Result<List<BaseMessage>>> fetchPreviousMessages({...});
      Future<Result<List<BaseMessage>>> fetchNextMessages({...});
      Future<Result<void>> markAsRead(BaseMessage message);
      Future<Result<void>> markAsDelivered(BaseMessage message);
      Future<Result<User?>> getLoggedInUser();
      Future<Result<Conversation>> getConversation({...});
      Future<Result<Conversation>> markMessageAsUnread(BaseMessage message);
    }
    ```
  </Tab>
</Tabs>

***

### 3. Wiring via the Service Locator

The service locators are the injection point. Both are singletons with a `setup()` method. Call `reset()` first, then `setup()` with your custom implementations before the widget mounts.

#### Datasource-level override (Conversations)

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    class MyConversationsRemoteDataSource implements ConversationsRemoteDataSource {
      @override
      Future<List<Conversation>> getConversations({int limit = 30, String? fromId}) async {
        // Your REST API call, mock data, etc.
      }
      // ... implement remaining methods
    }

    // Before mounting CometChatConversations:
    await ConversationsServiceLocator.instance.reset();

    final remote = MyConversationsRemoteDataSource();
    final local = ConversationsLocalDataSourceImpl(); // keep default cache
    final repo = ConversationsRepositoryImpl(
      remoteDataSource: remote,
      localDataSource: local,
    );
    ```
  </Tab>
</Tabs>

#### Repository-level override (Message List)

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    class MyMessageListRepository implements MessageListRepository {
      @override
      Future<Result<List<BaseMessage>>> getMessages({...}) async {
        // Custom logic
      }
      // ...
    }

    // Before mounting CometChatMessageList:
    await MessageListServiceLocator.instance.reset();
    // Wire your repo into use cases and pass to the BLoC
    ```
  </Tab>
</Tabs>

***

### Key Points

| Point                                            | Detail                                                                                                                                                                         |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `reset()`                                        | Sets `_isInitialized = false` — always call before re-wiring                                                                                                                   |
| `setup()`                                        | Guarded by `_isInitialized` — safe to call multiple times normally                                                                                                             |
| `localDataSource` in `MessageListRepositoryImpl` | Optional — pass `null` to disable caching entirely                                                                                                                             |
| Fallback caching                                 | `ConversationsRepositoryImpl` falls back to local cache when remote fails — your custom remote inherits this if you use `ConversationsRepositoryImpl` with a custom datasource |
| `Result<T>`                                      | All repository methods return `Result<T>` (`Success`/`Failure`) — your implementations must do the same                                                                        |
