ChannelList

ChannelList displays channels using React Native's FlatList.

ChannelList fetches channels via the client's query channels function. Pass filterssort, and options via props.

Use onSelect to handle navigation when a user taps a channel.

Best Practices

  • Memoize filters and sort to avoid unnecessary re-queries.
  • Keep onSelect lightweight and handle navigation outside of render.
  • Handle notification.message_new/message.new if you need strict filtering on real-time updates.
  • Avoid passing Channel instances through navigation params; store them in state instead.
  • Use sensible loadMoreThreshold values to reduce extra queries.

General Usage

ChannelList renders channels in a FlatList.

Note: Define the component within OverlayProvider and Chat so the required contexts are available.

import { StreamChat } from 'stream-chat';
import { ChannelList, Chat, OverlayProvider } from 'stream-chat-react-native';

const client = StreamChat.getInstance('api_key');
const filters = { members: { $in: [ 'vishal', 'lucas', 'neil' ] } };
const sort = { last_updated: -1 };
const options = { limit: 20, messages_limit: 30 };

export const App = () => <OverlayProvider>
    <Chat client={client}>
      <ChannelList
        filters={filters}
        sort={sort}
        options={options}
        onSelect={(channel) => /** navigate to channel screen */ }
      />
    </Chat>
  </OverlayProvider>;

Complete navigation example

Here's a practical example showing how to integrate ChannelList with React Navigation:

import React, { useMemo, useState, useEffect } from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import {
  Chat,
  OverlayProvider,
  ChannelList,
  Channel,
  MessageList,
  MessageInput,
  useCreateChatClient,
  useChatContext,
} from "stream-chat-react-native";

const Stack = createStackNavigator();

const ChannelListScreen = ({ navigation }) => {
  // Memoize filters and sort to prevent unnecessary re-renders
  const filters = useMemo(
    () => ({ members: { $in: ["user-id"] }, type: "messaging" }),
    [],
  );
  const sort = useMemo(() => [{ last_message_at: -1 }], []);

  return (
    <ChannelList
      filters={filters}
      sort={sort}
      onSelect={(channel) => {
        // Navigate to the channel screen
        // Note: Passing the channel CID, not the channel object
        navigation.navigate("Channel", { channelId: channel.cid });
      }}
    />
  );
};

const ChannelScreen = ({ route }) => {
  const { channelId } = route.params;
  const [channel, setChannel] = useState();
  const { client } = useChatContext();

  useEffect(() => {
    // Extract channel type and ID from CID (format: "type:id")
    const [type, id] = channelId.split(":");
    const channelInstance = client.channel(type, id);
    setChannel(channelInstance);
  }, [channelId, client]);

  if (!channel) return null;

  return (
    <Channel channel={channel}>
      <MessageList />
      <MessageInput />
    </Channel>
  );
};

export const App = () => {
  const chatClient = useCreateChatClient({
    apiKey: "YOUR_API_KEY",
    userData: { id: "user-id", name: "User Name" },
    tokenOrProvider: "YOUR_TOKEN",
  });

  if (!chatClient) return null;

  return (
    <OverlayProvider>
      <Chat client={chatClient}>
        <NavigationContainer>
          <Stack.Navigator>
            <Stack.Screen name="Channels" component={ChannelListScreen} />
            <Stack.Screen name="Channel" component={ChannelScreen} />
          </Stack.Navigator>
        </NavigationContainer>
      </Chat>
    </OverlayProvider>
  );
};

When using navigation, pass the channel CID (e.g., "messaging:channel-id") instead of the channel object, since Channel instances are not serializable and will cause React Navigation warnings.

When channels are added via events, filters are not applied (filters can be complex and aren't re-evaluated client-side). If you need strict filtering, override notification.message_new via onNewMessageNotification and message.new via onNewMessage.

Context Providers

ChannelList provides ChannelsContext, accessible via its hook.

ContextHook
ChannelsContextuseChannelsContext

Props

filters

Filter object passed to query channels. You can filter on built-in and custom fields.

For best performance, pass a stable reference (not created inline), or memoize it.

Type
Object

sort

Sort object passed to query channels. You can sort on built-in and custom fields.

For best performance, pass a stable reference (not created inline), or memoize it.

Type
Object

options

Options object passed internally to the client query function as a parameter.

Unlike the filters or sort objects, changing the options object alone will not re-query the list of channels.

Type
Object

onSelect

Called when a user taps a channel. Receives the Channel instance for that item and is often used for navigation.

Channel instances are not serializable, so passing them through navigation params will warn.

Type
(channel) ⇒ void

additionalFlatListProps

Additional props provided to the underlying FlatList.

Type
Object

loadMoreThreshold

Sets the onEndReachedThreshold. We recommend 0.1; higher values may trigger extra channelQuery calls.

TypeDefault
Number0.1

lockChannelOrder

Locks the order of the channels in the list so they will not dynamically reorder by most recent message when a new message is received.

TypeDefault
Booleanfalse

maxUnreadCount

Max unread badge value. Cannot exceed 255 (backend limit).

TypeDefault
Number255

numberOfSkeletons

The number of Skeleton items to display in the LoadingIndicator.

TypeDefault
Number6

onAddedToChannel

Override the default handler for when the user is added to a channel (default adds the channel).

Type
Function
ParameterDescription
setChannelsSetter function for the internal channels state
eventEvent Object corresponding to notification.added_to_channel
optionsChannelListEventListenerOptions object

onChannelDeleted

Override the default handler for channel deletion (default removes the channel).

Type
Function
ParameterDescription
setChannelsSetter function for the internal channels state
eventEvent Object corresponding to channel.deleted

onChannelHidden

Override the default handler for channel hidden (default removes the channel).

Type
Function
ParameterDescription
setChannelsSetter function for the internal channels state
eventEvent Object corresponding to channel.deleted

onChannelMemberUpdated

Override the default handler for member.updated. Required for pinning and archiving to work.

Type
Function
ParameterDescription
lockChannelOrderLocks the order of the channels in the list so they will not dynamically reorder by most recent message when a new message is received.
setChannelsSetter function for the internal channels state.
eventEvent Object corresponding to message.new.
optionsChannelListEventListenerOptions object

onChannelVisible

Override the default handler for channel visible (default adds the channel).

Type
Function
ParameterDescription
setChannelsSetter function for the internal channels state
eventEvent Object corresponding to channel.deleted

onChannelTruncated

Override the default handler for channel truncated (default reloads the list).

Type
Function
ParameterDescription
setChannelsSetter function for the internal channels state
eventEvent Object corresponding to channel.deleted

onChannelUpdated

Override the default handler for channel updated (default updates the channel data from the event).

Type
Function
ParameterDescription
setChannelsSetter function for the internal channels state
eventEvent Object corresponding to channel.deleted

onNewMessageNotification

Override the default handler for new message on an unwatched channel (default adds the channel).

Type
Function
ParameterDescription
setChannelsSetter function for the internal channels state
eventEvent Object corresponding to channel.deleted
optionsChannelListEventListenerOptions object

onNewMessage

Override the default handler for new message on a watched channel (default moves the channel to the top).

Type
Function
ParameterDescription
lockChannelOrderLocks the order of the channels in the list so they will not dynamically reorder by most recent message when a new message is received.
setChannelsSetter function for the internal channels state.
eventEvent Object corresponding to message.new.
optionsChannelListEventListenerOptions object

onRemovedFromChannel

Override the default handler for when the user is removed from a channel (default removes the channel).

Type
Function
ParameterDescription
setChannelsSetter function for the internal channels state.
eventEvent Object corresponding to channel.deleted.

setFlatlistRef

Callback function to access the underlying FlatList ref.

Type
(ref) ⇒ void

queryChannelsOverride

A function that overrides the ChannelManager queryChannels method (StreamChat.queryChannels). Use it to query specific cids while still paginating (not possible via normal filters). Rules/assumptions:

  • StreamChat.queryChannels must be called inside queryChannelsOverride (it updates important client state)
  • The return type has to be Channel[] (which is the return type of StreamChat.queryChannels)
  • limit and offset must still be respected so ChannelManager can paginate correctly
Type
QueryChannelsRequestType

Available since version 8.2.0.

filters and sort should still be stable/memoized. Do not change filters to pass different cids; handle that inside queryChannelsOverride based on pagination params from ChannelManager.

Example override:

const cids = Array.from({ length: 25 }, (_, i) => (i + 1).toString());

const queryChannelsOverride = (filters, sort, options, ...restParams) => {
  const { limit, offset } = options;

  const cidWindow = cids.slice(offset, offset + limit);
  const newFilters = { ...filters, cid: { $in: cidWindow } };

  return chatClient.queryChannels(newFilters, sort, options, ...restParams);
};

Given this ChannelList configuration:

// ... rest of the component
const filters = useMemo(() => ({}), []);
const options = useMemo(() => ({ offset: 0, limit: 10 }));
return <ChannelList filters={stableFilters} options={options} />;

Pagination works as follows:

  1. On the first page, 10 items will be loaded, which will be the first 10 cids
  2. On the second page, queryChannelsOverride will be invoked with offset: 10 and limit: 10, so cids 10 through 19 will be loaded
  3. On the last page, queryChannelsOverride will be invoked with offset: 10 and limit: 10, and so our implementation will return the last 5 cids (and the ChannelManager will at this point determine there are no pages left)

UI Component Props

EmptyStateIndicator

Rendered when the channel list is empty and not loading via the ListEmptyComponent prop on the FlatList.

TypeDefault Value
ComponentTypeundefined | EmptyStateIndicator

FooterLoadingIndicator

Rendered when loadingNextPage from ChannelsContext is true via the ListFooterComponent prop on the FlatList.

TypeDefault Value
ComponentTypeundefined | ChannelListFooterLoadingIndicator

HeaderErrorIndicator

Rendered when error from ChannelsContext is true.

TypeDefault
ComponentTypeundefined | ChannelListHeaderErrorIndicator

HeaderNetworkDownIndicator

Rendered when isOnline from ChatContext is false.

TypeDefault
ComponentTypeundefined | ChannelListHeaderNetworkDownIndicator

List

Component to render the list of channels.

TypeDefault
ComponentTypeundefined | ChannelListMessenger

ListHeaderComponent

Rendered when provided if the channel list is not empty via the ListHeaderComponent prop on the FlatList.

Type
ComponentType |undefined

LoadingErrorIndicator

Rendered when error from ChannelsContext is true, and the channel list is empty and not loading.

TypeDefault
ComponentTypeundefined | LoadingErrorIndicator

LoadingIndicator

Rendered when the channel list is empty and loading via the ListEmptyComponent prop on the FlatList.

TypeDefault
ComponentTypeundefined | ChannelListLoadingIndicator

Preview

List item rendered by the underlying FlatList.

TypeDefault
ComponentTypeundefined | ChannelPreviewMessenger

PreviewAvatar

Avatar component rendered within Preview.

TypeDefault
ComponentTypeundefined | ChannelAvatar

PreviewMessage

Message component rendered within Preview.

TypeDefault
ComponentTypeundefined | ChannelPreviewMessage

PreviewMutedStatus

Channel muted status component rendered within Preview.

TypeDefault
ComponentTypeundefined | ChannelPreviewMutedStatus

PreviewStatus

Status component rendered within Preview.

TypeDefault
ComponentTypeundefined | ChannelPreviewStatus

PreviewTitle

Title component rendered within Preview.

TypeDefault
ComponentTypeundefined | ChannelPreviewTitle

PreviewUnreadCount

Unread count component rendered within Preview.

TypeDefault
ComponentTypeundefined | ChannelPreviewUnreadCount

Skeleton

Row item rendered in the LoadingIndicator.

TypeDefault
ComponentTypeundefined | Skeleton

Channel List Event Listener Options

filters

Filter object passed internally to the client query function as a parameter. You can filter a query on built-in and custom fields on a Channel.

Type
Object

sort

Sort object passed internally to the client query function as a parameter. You can sort a query on built-in and custom fields on a Channel.

Type
Object