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 image
  • ChannelSearch - renders channel search input and results
  • EmptyStateIndicator - rendered when the channels query returns an empty array
  • LoadingErrorIndicator - rendered when the channels query fails
  • LoadingIndicator- rendered during the channels query
  • List - component rendering LoadingErrorIndicator, LoadingIndicator, EmptyStateIndicator, Paginator and the list of channel Preview components
  • Paginator - 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 setChannels until the initial query completes to avoid overwrites.
  • Keep custom list components aligned with the default loading/error states.
  • Use Paginator for 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:

import { useChannelListContext } from "stream-chat-react";

export const CustomComponent = () => {
  const { channels, setChannels } = useChannelListContext();
  // component logic ...
  return {
    /* rendered elements */
  };
};

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[]>>