import { useChannelListContext } from "stream-chat-react";
export const CustomComponent = () => {
const { channels, setChannels } = useChannelListContext();
// component logic ...
return {
/* rendered elements */
};
};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. Components that can consume ChannelListContext are customizable via ChannelListProps:
Avatar- component used to display channel imageChannelSearch- renders channel search input and resultsEmptyStateIndicator- rendered when the channels query returns an empty arrayLoadingErrorIndicator- rendered when the channels query failsLoadingIndicator- rendered during the channels queryList- component renderingLoadingErrorIndicator,LoadingIndicator,EmptyStateIndicator,Paginatorand the list of channelPreviewcomponentsPaginator- takes care of requesting to load more channels into the list (pagination)Preview- renders the information of a channel in the channel list
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. - Gate expensive logic to avoid blocking list rendering.
Basic Usage
Access the API from ChannelListContext with our custom hook:
Values
channels
State representing the array of loaded channels. By default, the channels query is executed by ChannelList.
| Type |
|---|
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.
The example below sets the active channel from the URL. It waits for the first page, then falls back to getChannel() if the channel isn’t in that page:
import { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { ChannelList, ChannelListMessenger, ChannelListMessengerProps, getChannel, useChannelListContext, useChatContext } from 'stream-chat-react';
const DEFAULT_CHANNEL_ID = 'general';
const DEFAULT_CHANNEL_TYPE = 'messaging';
const List = (props: ChannelListMessengerProps) => {
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 <ChannelListMessenger {...props}/>;
};
const Sidebar = () => {
return (
// ...
<ChannelList
{/* some props */}
{/* setting active channel will be performed inside the custom List component */}
setActiveChannelOnMount={false}
List={List}
{/* some props */}
/>
// ...
}| Type |
|---|
Dispatch<SetStateAction<Channel[]>> |