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>;ChannelList
ChannelList displays channels using React Native's FlatList.
ChannelList fetches channels via the client's query channels function. Pass filters, sort, and options via props.
Use onSelect to handle navigation when a user taps a channel.
Best Practices
- Memoize
filtersandsortto avoid unnecessary re-queries. - Keep
onSelectlightweight and handle navigation outside of render. - Handle
notification.message_new/message.newif you need strict filtering on real-time updates. - Avoid passing
Channelinstances through navigation params; store them in state instead. - Use sensible
loadMoreThresholdvalues to reduce extra queries.
General Usage
ChannelList renders channels in a FlatList.
Note: Define the component within
OverlayProviderandChatso the required contexts are available.
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.
| Context | Hook |
|---|---|
ChannelsContext | useChannelsContext |
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.
| 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.
| Type | Default |
|---|---|
| Number | 0.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.
| Type | Default |
|---|---|
| Boolean | false |
maxUnreadCount
Max unread badge value. Cannot exceed 255 (backend limit).
| Type | Default |
|---|---|
| Number | 255 |
numberOfSkeletons
The number of Skeleton items to display in the LoadingIndicator.
| Type | Default |
|---|---|
| Number | 6 |
onAddedToChannel
Override the default handler for when the user is added to a channel (default adds the channel).
| Type |
|---|
| Function |
| Parameter | Description |
|---|---|
| setChannels | Setter function for the internal channels state |
| event | Event Object corresponding to notification.added_to_channel |
| options | ChannelListEventListenerOptions object |
onChannelDeleted
Override the default handler for channel deletion (default removes the channel).
| Type |
|---|
| Function |
| Parameter | Description |
|---|---|
| setChannels | Setter function for the internal channels state |
| event | Event Object corresponding to channel.deleted |
onChannelHidden
Override the default handler for channel hidden (default removes the channel).
| Type |
|---|
| Function |
| Parameter | Description |
|---|---|
| setChannels | Setter function for the internal channels state |
| event | Event Object corresponding to channel.deleted |
onChannelMemberUpdated
Override the default handler for member.updated. Required for pinning and archiving to work.
| Type |
|---|
| Function |
| Parameter | Description |
|---|---|
| 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. |
| setChannels | Setter function for the internal channels state. |
| event | Event Object corresponding to message.new. |
| options | ChannelListEventListenerOptions object |
onChannelVisible
Override the default handler for channel visible (default adds the channel).
| Type |
|---|
| Function |
| Parameter | Description |
|---|---|
| setChannels | Setter function for the internal channels state |
| event | Event Object corresponding to channel.deleted |
onChannelTruncated
Override the default handler for channel truncated (default reloads the list).
| Type |
|---|
| Function |
| Parameter | Description |
|---|---|
| setChannels | Setter function for the internal channels state |
| event | Event Object corresponding to channel.deleted |
onChannelUpdated
Override the default handler for channel updated (default updates the channel data from the event).
| Type |
|---|
| Function |
| Parameter | Description |
|---|---|
| setChannels | Setter function for the internal channels state |
| event | Event Object corresponding to channel.deleted |
onNewMessageNotification
Override the default handler for new message on an unwatched channel (default adds the channel).
| Type |
|---|
| Function |
| Parameter | Description |
|---|---|
| setChannels | Setter function for the internal channels state |
| event | Event Object corresponding to channel.deleted |
| options | ChannelListEventListenerOptions object |
onNewMessage
Override the default handler for new message on a watched channel (default moves the channel to the top).
| Type |
|---|
| Function |
| Parameter | Description |
|---|---|
| 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. |
| setChannels | Setter function for the internal channels state. |
| event | Event Object corresponding to message.new. |
| options | ChannelListEventListenerOptions object |
onRemovedFromChannel
Override the default handler for when the user is removed from a channel (default removes the channel).
| Type |
|---|
| Function |
| Parameter | Description |
|---|---|
| setChannels | Setter function for the internal channels state. |
| event | Event 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.queryChannelsmust be called insidequeryChannelsOverride(it updates important client state)- The return type has to be
Channel[](which is the return type ofStreamChat.queryChannels) limitandoffsetmust still be respected soChannelManagercan 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:
- On the first page, 10 items will be loaded, which will be the first 10
cids - On the second page,
queryChannelsOverridewill be invoked withoffset: 10andlimit: 10, socids10through19will be loaded - On the last page,
queryChannelsOverridewill be invoked withoffset: 10andlimit: 10, and so our implementation will return the last 5cids (and theChannelManagerwill 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.
| Type | Default Value |
|---|---|
| ComponentType | undefined | EmptyStateIndicator |
FooterLoadingIndicator
Rendered when loadingNextPage from ChannelsContext is true via the ListFooterComponent prop on the FlatList.
| Type | Default Value |
|---|---|
| ComponentType | undefined | ChannelListFooterLoadingIndicator |
HeaderErrorIndicator
Rendered when error from ChannelsContext is true.
| Type | Default |
|---|---|
| ComponentType | undefined | ChannelListHeaderErrorIndicator |
HeaderNetworkDownIndicator
Rendered when isOnline from ChatContext is false.
| Type | Default |
|---|---|
| ComponentType | undefined | ChannelListHeaderNetworkDownIndicator |
List
Component to render the list of channels.
| Type | Default |
|---|---|
| ComponentType | undefined | 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.
| Type | Default |
|---|---|
| ComponentType | undefined | LoadingErrorIndicator |
LoadingIndicator
Rendered when the channel list is empty and loading via the ListEmptyComponent prop on the FlatList.
| Type | Default |
|---|---|
| ComponentType | undefined | ChannelListLoadingIndicator |
Preview
List item rendered by the underlying FlatList.
| Type | Default |
|---|---|
| ComponentType | undefined | ChannelPreviewMessenger |
PreviewAvatar
Avatar component rendered within Preview.
| Type | Default |
|---|---|
| ComponentType | undefined | ChannelAvatar |
PreviewMessage
Message component rendered within Preview.
| Type | Default |
|---|---|
| ComponentType | undefined | ChannelPreviewMessage |
PreviewMutedStatus
Channel muted status component rendered within Preview.
| Type | Default |
|---|---|
| ComponentType | undefined | ChannelPreviewMutedStatus |
PreviewStatus
Status component rendered within Preview.
| Type | Default |
|---|---|
| ComponentType | undefined | ChannelPreviewStatus |
PreviewTitle
Title component rendered within Preview.
| Type | Default |
|---|---|
| ComponentType | undefined | ChannelPreviewTitle |
PreviewUnreadCount
Unread count component rendered within Preview.
| Type | Default |
|---|---|
| ComponentType | undefined | ChannelPreviewUnreadCount |
Skeleton
Row item rendered in the LoadingIndicator.
| Type | Default |
|---|---|
| ComponentType | undefined | 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 |
- Best Practices
- General Usage
- Context Providers
- Props
- filters
- sort
- options
- onSelect
- additionalFlatListProps
- loadMoreThreshold
- lockChannelOrder
- maxUnreadCount
- numberOfSkeletons
- onAddedToChannel
- onChannelDeleted
- onChannelHidden
- onChannelMemberUpdated
- onChannelVisible
- onChannelTruncated
- onChannelUpdated
- onNewMessageNotification
- onNewMessage
- onRemovedFromChannel
- setFlatlistRef
- queryChannelsOverride
- UI Component Props
- Channel List Event Listener Options