const Users = () => {
const { channel } = useChannelStateContext();
const [channelUsers, setChannelUsers] = useState<
Array<{ name: string; online: boolean }>
>([]);
useEffect(() => {
const updateChannelUsers = () => {
setChannelUsers(
Object.values(channel.state.members).map((user) => ({
name: user.user_id!,
online: !!user.user!.online,
})),
);
};
updateChannelUsers();
}, [client, channel]);
return (
<ul className="users-list">
{channelUsers.map((member) => (
<li key={member.name}>
{member.name} - {member.online ? "online" : "offline"}
</li>
))}
</ul>
);
};Channel Members and Online Status
In this example, we will demonstrate how to render the current channel members and their online status.
Best Practices
- Use
useChannelStateContextfor members and supplement with presence events. - Watch the channel with presence enabled before relying on online status.
- Filter presence updates to the active channel to avoid unnecessary renders.
- Keep the list UI simple to prevent frequent reflow on status changes.
- Clean up event listeners on unmount to prevent memory leaks.
Render the Channel Members List
Let’s start by creating a simple members list component. To access members, read the current channel via useChannelStateContext.
The example is a bit more convoluted, since we will add online presence updates at the next step.
To receive presence updates, watch the channel with channel.watch({ presence: true }). See the JavaScript docs.
We can place the component as a child of the Channel component:
<Channel>
<Window>
<Users />
<ChannelHeader />
<MessageList />
<MessageInput focus />
</Window>
<Thread />
</Channel>Real-Time Updates
So far the list looks good, but there’s a catch: useChannelStateContext doesn’t refresh on presence changes for performance reasons.
To make the list update accordingly, we need to attach an additional listener to the user.presence.changed event of the chat client.
Add some basic CSS to complete the list. The class is already applied in JSX; import the CSS in your component.
.users-list {
background: #ffffff;
padding: 20px;
padding-left: 30px;
border-radius: calc(16px / 2) 16px 0 0;
border: 1px solid #ecebeb;
}const Users = () => {
const { client } = useChatContext();
const { channel } = useChannelStateContext();
const [channelUsers, setChannelUsers] = useState<
Array<{ name: string; online: boolean }>
>([]);
useEffect(() => {
const updateChannelUsers = (event?: Event) => {
// test if the updated user is a member of this channel
if (!event || channel.state.members[event.user!.id] !== undefined) {
setChannelUsers(
Object.values(channel.state.members).map((user) => ({
name: user.user_id!,
online: !!user.user!.online,
})),
);
}
};
updateChannelUsers();
client.on("user.presence.changed", updateChannelUsers);
return () => {
client.off("user.presence.changed", updateChannelUsers);
};
}, [client, channel]);
return (
<ul className="users-list">
{channelUsers.map((member) => (
<li key={member.name}>
{member.name} - {member.online ? "online" : "offline"}
</li>
))}
</ul>
);
};With the above addition, channelUsers will be updated each time user comes online or goes offline.