# ChannelList

> **Info:** This is release candidate documentation for **Stream Chat React Native SDK v10**. For the latest stable version, see the [latest version (v9)](https://getstream.io/chat/docs/sdk/react-native/).

`ChannelList` renders the channels of one `ChannelPaginator`, a row per channel, and loads the next page as the user scrolls. The paginator holds the query and the loaded channels; the list only renders them. [Channel list UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/channel-list-ui/) explains what the list renders and reads, and [Channel lists](https://getstream.io/chat/docs/sdk/react-native/v10/features/channels/channel-lists/) covers the feature end to end.

## Best practices

- Create the paginator once for the user, not on every render, and register it on `client.channelManager`. An unregistered paginator shows its first page and then never changes.
- Scope the paginator's filters to the user, for example with `members: { $in: [userId] }`. Without that, a list can show channels the user isn't a member of.
- Give each list its own paginator with its own `id`.
- Remove and dispose of the paginator when the user signs out. `ChannelList` never disposes of it.
- Pass `onSelect`, and open the channel from it. The list holds no selection and doesn't navigate.

## Rendering a list

Create a paginator, register it on `client.channelManager`, and pass it to `ChannelList`:

```tsx title="src/ChannelListScreen.tsx"
import { useEffect, useMemo } from "react";
import { ChannelPaginator } from "stream-chat";
import type { Channel, ChannelFilters, SortParamRequest } from "stream-chat";
import { ChannelList, useChatContext } from "stream-chat-react-native";

const sort: SortParamRequest[] = [{ direction: -1, field: "last_message_at" }];

export const ChannelListScreen = ({
  onSelect,
  userId,
}: {
  onSelect: (channel: Channel) => void;
  userId: string;
}) => {
  const { client } = useChatContext();

  const paginator = useMemo(() => {
    const filters: ChannelFilters = {
      members: { $in: [userId] },
      type: "messaging",
    };
    return new ChannelPaginator({ client, filters, id: "inbox", sort });
  }, [client, userId]);

  // A registered list is kept up to date as events arrive.
  useEffect(() => {
    client.channelManager.insertPaginator({ paginator });
    return () => {
      client.channelManager.removePaginator(paginator);
      paginator.dispose();
    };
  }, [client, paginator]);

  return <ChannelList onSelect={onSelect} paginator={paginator} />;
};
```

Here the screen owns the paginator, so it's disposed of when the screen unmounts. An app that keeps the list's channels across screens creates the paginator next to the client instead. Filters, sort, registering and disposing are explained on [Channel list paginators](https://getstream.io/chat/docs/sdk/react-native/v10/state/loading-data/channel-list-paginators/).

## What it does

- Loads the first page when the paginator has none and a user is connected: on mount, when it gets another paginator, and after `client.disconnectUser()` resets the paginator. A paginator that already holds channels is shown as it is.
- Loads the next page when the user scrolls within `loadMoreThreshold` of the end.
- Refreshes the first page when the user pulls the list down, keeping the loaded channels on screen. A pull within 5 seconds of the last refresh, or of the list mounting, is ignored unless the last query failed.
- Starts the event subscriptions of `client.channelManager` while it's mounted. Every mounted list shares them, and they stop when the last list unmounts.
- Provides [`ChannelsContext`](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel-list/channelscontext/) to its rows, and renders a `NotificationList` for the notifications aimed at the list.

It renders the rows in [`ChannelListView`](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel-list/channel-list-view/), a React Native `FlatList`.

## UI customization

Register replacements with `WithComponents`. `ChannelList` and the parts it renders read these keys:

| Override key                            | Replaces                                                                          | Gets                                                    |
| --------------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------- |
| `ChannelPreview`                        | The content of each row. The default is `ChannelPreviewView`.                     | `channel`, `muted`, `pinned`, `unread`, `lastMessage`   |
| `ChannelListLoadingIndicator`           | The placeholder rows while the first page loads                                   | nothing                                                 |
| `Skeleton`                              | Each placeholder row                                                              | nothing                                                 |
| `ChannelListFooterLoadingIndicator`     | The spinner after the last row while the next page loads                          | nothing                                                 |
| `EmptyStateIndicator`                   | "No conversations yet", when the list has no channels                             | `listType: 'channel'`                                   |
| `LoadingErrorIndicator`                 | The error state when the first page fails. Tapping it loads the first page again. | `error`, `listType: 'channel'`, `loadNextPage`, `retry` |
| `ChannelListHeaderErrorIndicator`       | The banner over the list when a query fails while channels are on screen          | `onPress`, which refreshes the list                     |
| `ChannelListHeaderNetworkDownIndicator` | The "Reconnecting..." banner while the network or the WebSocket is down           | nothing                                                 |
| `ListHeaderComponent`                   | Nothing by default. Rendered above the first row, and scrolls with the list.      | nothing                                                 |
| `NotificationList`                      | The list's notifications                                                          | nothing                                                 |

The row's parts, such as the title and the unread badge, have keys of their own; see [Channel preview](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel-list/channel-preview/). `ChannelList` itself has no override key.

`EmptyStateIndicator` and `LoadingErrorIndicator` are shared with the message list, which passes `listType: 'message'`, so a replacement checks `listType`. [Loading, empty and error states](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/channel-list-ui/#loading-empty-and-error-states) explains when each one shows.

## Props

| Prop                      | Type                                           | Default                             | Description                                                                                                                                                                          |
| ------------------------- | ---------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `paginator`               | `ChannelPaginator`                             | required                            | The paginator whose channels the list renders. Register it on `client.channelManager`.                                                                                               |
| `additionalFlatListProps` | `Partial<FlatListProps<Channel>>`              | `{}`                                | Props spread on the `FlatList` after the ones the list sets, so they take precedence. Use `setFlatListRef` for the ref.                                                              |
| `channelRenderFilterFn`   | `(channels: Array<Channel>) => Array<Channel>` |                                     | Filters the loaded channels before they render. It runs on every render of the list, so keep it a cheap pure function. The paginator still holds every channel.                      |
| `getChannelActionItems`   | `GetChannelActionItems`                        | the default items                   | Receives the default channel actions of a row and returns the ones to show. See [Changing the items](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/actions/#changing-the-items).    |
| `loadMoreThreshold`       | `number`                                       | `0.1`                               | How close to the end the user scrolls before the next page loads, in multiples of the list's visible length: the `FlatList`'s `onEndReachedThreshold`.                               |
| `maxUnreadCount`          | `number`                                       | `255`                               | The highest count the unread badge shows. A larger count shows as this number.                                                                                                       |
| `mutedStatusPosition`     | `'trailingBottom' \| 'inlineTitle'`            | `'inlineTitle'`                     | Where a muted channel's icon shows: next to the title, or at the end of the message line.                                                                                            |
| `notificationHostId`      | `string`                                       | a random id the list generates once | The notification host of the list's `NotificationList`. See [Routing notifications](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/displaying-notifications/#routing-notifications). |
| `numberOfSkeletons`       | `number`                                       | `8`                                 | The number of placeholder rows while the first page loads.                                                                                                                           |
| `onSelect`                | `(channel: Channel) => void`                   |                                     | Runs when the user taps a row, with its channel. While a row's swipe actions are open, a tap closes them instead. Without it, a tap does nothing else.                               |
| `pinnedStatusPosition`    | `'trailingBottom' \| 'inlineTitle'`            | `'inlineTitle'`                     | Where a pinned channel's icon shows: next to the title, or at the end of the message line.                                                                                           |
| `setFlatListRef`          | `(ref: FlatList<Channel> \| null) => void`     |                                     | Receives the list's `FlatList` ref, and `null` when it unmounts.                                                                                                                     |
| `swipeActionsEnabled`     | `boolean`                                      | `true`                              | Lets the user swipe a row to reveal its actions. See [Swipe actions](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/channel-list-ui/#swipe-actions).                                  |

The `FlatList` in the type of `setFlatListRef` is the one from `react-native-gesture-handler`; the list renders React Native's.

Everything else about a list is set on its paginator and on `client.channelManager`: filters, sort, page size, and how events move channels between lists. See [Channel list paginators](https://getstream.io/chat/docs/sdk/react-native/v10/state/loading-data/channel-list-paginators/) and [Channel manager and ChannelPaginator](https://getstream.io/chat/docs/sdk/react-native/v10/reference/state/channel-manager-and-channelpaginator/).

## Examples

### Scroll to the top

```tsx title="src/ScrollableChannelList.tsx"
import { useRef } from "react";
import { Button, View } from "react-native";
import type { Channel, ChannelPaginator } from "stream-chat";
import { ChannelList } from "stream-chat-react-native";

type ListRef = {
  scrollToOffset: (params: { animated?: boolean; offset: number }) => void;
};

export const ScrollableChannelList = ({
  onSelect,
  paginator,
}: {
  onSelect: (channel: Channel) => void;
  paginator: ChannelPaginator;
}) => {
  const listRef = useRef<ListRef | null>(null);

  return (
    <View style={{ flex: 1 }}>
      <Button
        onPress={() =>
          listRef.current?.scrollToOffset({ animated: true, offset: 0 })
        }
        title="Back to top"
      />
      <ChannelList
        onSelect={onSelect}
        paginator={paginator}
        setFlatListRef={(ref) => {
          listRef.current = ref;
        }}
      />
    </View>
  );
};
```

### Several lists

Register one paginator per list, each with its own `id`, and render one `ChannelList` for each. [Several lists](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/channel-list-ui/#several-lists) has an example with tabs.

### Change the query

Set the paginator's `staticFilters` or `sort`, and reload it, or create a paginator with another `id`. [Changing filters or sort](https://getstream.io/chat/docs/sdk/react-native/v10/state/loading-data/channel-list-paginators/#changing-filters-or-sort) shows both.

## Related hooks

- `useChannelsContext()` returns [`ChannelsContext`](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel-list/channelscontext/) inside a list: the paginator, the list's configuration and its loading functions.
- `useStateStore(paginator.state, selector)` reads the loaded channels and whether more are loading. See [Loading data hooks](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/loading-data-hooks/).
- The hooks a row uses, such as `useChannelPreviewDisplayName`, are on [Channel preview hooks](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/channel-preview-hooks/).

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel-list/channellist/](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel-list/channellist/).