Channel
Channel binds one channel to the components inside it. It activates the channel while it's mounted, renders the channel's container around its children, and stops the channel's audio players when the channel changes. It doesn't load the channel. Channel UI explains what it does, and Reading state in components how its children read the channel's state.
Best practices
- Pass a channel that is already watched, for example with
Channel.watch(). A channel from a channel list is loaded already, and the SDK's search results watch the channel they open. - With
ChatView, letChannelSlotrenderChannelfor the channel in its slot. See Workspace with ChatView. - Read the channel in its children with
useChannel(), and its state withuseStateStore, rather than passing them down as props. Channeltakes no component props. Replace the parts inside it withWithComponents, or by rendering different children.- While no channel is selected, render
ChannelPlaceholderin its place.
Basic usage
import {
Channel,
ChannelHeader,
MessageComposer,
MessageList,
} from "stream-chat-react";
export const ChannelPanel = () => (
<Channel channel={channel}>
<ChannelHeader />
<MessageList />
<MessageComposer />
</Channel>
);MessageList renders channel.messagePaginator, and MessageComposer writes into channel.messageComposer. A component of your own reads the same channel:
import type { ChannelStateData } from "stream-chat";
import { useChannel, useStateStore } from "stream-chat-react";
const frozenSelector = ({ data }: ChannelStateData) => ({
frozen: data?.frozen,
});
export const FrozenBanner = () => {
const channel = useChannel();
const { frozen } = useStateStore(channel.state, frozenSelector);
if (!frozen) return null;
return <div className="frozen-banner">This channel is read-only.</div>;
};Props
| Prop | Type | Default | Description |
|---|---|---|---|
channel |
Channel from stream-chat |
required | The channel to bind. Watch it before you pass it. Channel activates it while mounted, so it stays loaded and is reloaded after a reconnect; see Entity lifecycle. |
Channel takes nothing else. The props it took in v14 are listed in Upgrade to v15.
ChannelPlaceholder takes the props of a div. It renders the same container as Channel, with the classes str-chat, the theme classes and str-chat__channel, but with no channel bound. Its className is added to those classes.
Examples
Watch the channel before passing it
import { useEffect, useState } from "react";
import type { Channel as StreamChannel } from "stream-chat";
import {
Channel,
ChannelHeader,
MessageComposer,
MessageList,
useChatContext,
} from "stream-chat-react";
export const SupportChannel = ({ channelId }: { channelId: string }) => {
const { client } = useChatContext();
const [channel, setChannel] = useState<StreamChannel>();
useEffect(() => {
let cancelled = false;
client
.channel("messaging", channelId)
.watch()
.then((watchedChannel) => {
if (!cancelled) setChannel(watchedChannel);
})
.catch((error) => console.error("Could not watch the channel", error));
return () => {
cancelled = true;
};
}, [channelId, client]);
if (!channel) return <div>Loading the channel...</div>;
return (
<Channel channel={channel}>
<ChannelHeader />
<MessageList />
<MessageComposer />
</Channel>
);
};Channel.watch() resolves with the channel instance to use from then on. Loading and error states are yours to render: Channel has no query to report on.
Render something while no channel is selected
import type { Channel as StreamChannel } from "stream-chat";
import {
Channel,
ChannelHeader,
ChannelPlaceholder,
MessageComposer,
MessageList,
} from "stream-chat-react";
export const ChannelArea = ({ channel }: { channel?: StreamChannel }) => {
if (!channel) {
return (
<ChannelPlaceholder>Pick a channel to start chatting.</ChannelPlaceholder>
);
}
return (
<Channel channel={channel}>
<ChannelHeader />
<MessageList />
<MessageComposer />
</Channel>
);
};Related hooks
| Hook | Returns |
|---|---|
useChannel() |
the channel: the thread's channel inside a Thread, otherwise the Channel's. Throws outside both |
useChannelInstanceContext() |
{ channel } inside a Channel, {} outside |
useMessageComposerController() |
the composer of the channel, or of the thread inside a Thread |
useStateStore(store, selector) |
a selection of a store, such as channel.state, that re-renders the component when it changes |
Reading state in components explains which owner each hook reads, and Channel and thread hooks lists the hooks for channel state.