import { useChannelListContext } from "stream-chat-react";
export const CustomComponent = () => {
const { channels, setChannels } = useChannelListContext();
// component logic ...
return {
/* rendered elements */
};
};This is beta documentation for Stream Chat React SDK v14. For the latest stable version, see the latest version (v13)
.
ChannelListContext
The context value is provided by ChannelListContextProvider, which wraps the content rendered by ChannelList.
It exposes API used by the default and custom components. In v14, SDK-owned channel list UI customization mainly flows through WithComponents / ComponentContext:
ChannelListUI- renders the list container, loading state, and error stateChannelListItemUI- renders the information for one channel rowAvatar- component used to display the channel image inside the default row UILoadingErrorIndicator- rendered when the channels query failsLoadingIndicator- rendered during the channels querySearch- renders the search input and results whenshowChannelSearchis enabledEmptyStateIndicator- still provided directly throughChannelListPaginator- still provided directly throughChannelList
Best Practices
- Read from context instead of passing channel list state down manually.
- Defer
setChannelsuntil the initial query completes to avoid overwrites. - Keep custom list components aligned with the default loading/error states.
- Use
Paginatorfor infinite scroll instead of DIY pagination. - Register SDK-owned channel list UI overrides through
WithComponents. - Gate expensive logic to avoid blocking list rendering.
Basic Usage
Access the API from ChannelListContext with our custom hook:
Values
| Value | Description | Type |
|---|---|---|
channels | State representing the array of loaded channels. By default, the channels query is executed by ChannelList. | Channel[] |
setChannels | Sets the list of channels rendered by ChannelList. Be careful when calling this early: the initial ChannelList query overwrites the whole channels state. A common pattern is to wait for the channels.queried event before calling setChannels. | Dispatch<SetStateAction<Channel[]>> |
Examples
Set the active channel from the URL
The example below waits for the first page, then falls back to getChannel() if the channel is not in that page:
import { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import type { Event } from 'stream-chat';
import {
ChannelList,
ChannelListUI,
type ChannelListUIProps,
WithComponents,
getChannel,
useChannelListContext,
useChatContext,
} from 'stream-chat-react';
const DEFAULT_CHANNEL_ID = 'general';
const DEFAULT_CHANNEL_TYPE = 'messaging';
const CustomChannelListUI = (props: ChannelListUIProps) => {
const { channelId } = useParams();
const navigate = useNavigate();
const { client, channel, setActiveChannel } = useChatContext();
const { setChannels } = useChannelListContext();
useEffect(() => {
if (!channelId) return navigate(`/${DEFAULT_CHANNEL_ID}`);
if (channel?.id === channelId || !client) return;
let subscription: { unsubscribe: () => void } | undefined;
if(!channel?.id || channel?.id !== channelId) {
subscription = client.on('channels.queried', (event: Event) => {
const loadedChannelData = event.queriedChannels?.channels.find((response) => response.channel.id === channelId);
if (loadedChannelData) {
setActiveChannel(client.channel( DEFAULT_CHANNEL_TYPE, channelId));
subscription?.unsubscribe();
return;
}
return getChannel({client, id: channelId, type: DEFAULT_CHANNEL_TYPE}).then((newActiveChannel) => {
setActiveChannel(newActiveChannel);
setChannels((channels) => {
return ([newActiveChannel, ...channels.filter((ch) => ch.data?.cid !== newActiveChannel.data?.cid)]);
});
});
});
}
return () => {
subscription?.unsubscribe();
};
}, [channel?.id, channelId, setChannels, client, navigate, setActiveChannel]);
return <ChannelListUI {...props} />;
};
const Sidebar = () => {
return (
<WithComponents overrides={{ ChannelListUI: CustomChannelListUI }}>
<ChannelList
{/* some props */}
{/* setting active channel will be performed inside the custom ChannelListUI component */}
setActiveChannelOnMount={false}
{/* some props */}
/>
</WithComponents>
);
};