Skip to main content
Version: v11

SDK State Management

Most of the application state which is the main driver behind the UI changes of our chat SDK lives within our low-level client (LLC) - StreamChat - more specifically client and channel instances and is NOT REACTIVE - our React SDK makes these state stores reactive by listening to the same events client does and copies it with the help of useState API after it has been changed. Optimistic updates - if applicable - are handled by and are local only to React SDK.

This is how the SDK state pipeline looks like behind the scenes:

Active Channel & Channel State

The SDK comes with ChatContext which holds (among other things) currently active channel instance and forwards LLC instance passed to the Chat component. Before you can access the reactive channel state you'll need to set the channel instance as active. The channel becomes active when:

  • it's user-selected in the ChannelList component (if you're using our (default setup), you probably already have ChannelList in your application)

  • it's passed to the channel prop of the Channel component

    import { useState, useEffect } from 'react';
    import { Channel, useChatContext } from 'stream-chat-react';

    export const ChannelWrapper = ({ channelId, channelType = 'messaging', children }) => {
    const [activeChannel, setActiveChannel] = useState(undefined);
    const { client } = useChatContext();

    useEffect(() => {
    if (!channelId) return;

    const channel = client.channel(channelId, channelType);

    setActiveChannel(channel);
    }, [channelId, channelType]);

    return <Channel channel={activeChannel}>{children}</Channel>;
    };
  • it's set as active by calling the setActiveChannel function coming from the ChatContext (this function is used by ChannelList behind the scenes)

    import { useEffect } from 'react';
    import { useCreateChatClient, useChatContext, Chat, Channel } from 'stream-chat-react';

    const ActiveChannelSetter = ({ channelId, channelType }) => {
    const { client, setActiveChannel } = useChatContext();

    useEffect(() => {
    const channel = client.channel(channelId, channelType);
    setActiveChannel(channel);
    }, [channelType, channelId]);

    return null;
    };

    const App = () => {
    const client = useCreateChatClient(userData);

    if (!client) return <div>Loading...</div>;

    return (
    <Chat client={client}>
    <ActiveChannelSetter channelId='random' channelType='messaging' />
    <Channel>{'...other components...'}</Channel>
    </Chat>
    );
    };
note

You can use either channel prop on the Channel component or setActiveChannel function. You cannot use both at the same time.

Currently active channel state and channel instance can be accessed through the ChannelStateContext with the help of the useChannelStateContext hook - meaning any component which is either direct or indirect child of the Channel component can access such state.

The example bellow shows how to reach members and channel property coming from the channel state:

import { useEffect } from 'react';
import { Channel, useChannelStateContext } from 'stream-chat-react';

const MembersCount = () => {
const { members, channel } = useChannelStateContext();

useEffect(() => {
console.log(`Currently active channel changed, channelId: ${channel.id}`);
}, [channel]);

return <div>{Object.keys(members).length}</div>;
};

const ChannelWrapper = () => (
<Channel>
<MembersCount />
</Channel>
);

Channel List State

ChannelList component is a standalone component which (unsurprisingly) holds and manages list of channels. You can access loaded channels from ChannelListContext with the help of useChannelListContext hook. Any component which is either direct or indirect child of the ChannelList component can access such state (Channel Preview for example).

import { ChannelList, ChannelPreviewMessenger } from 'stream-chat-react';
import type { ChannelListProps } from 'stream-chat-react';

const CustomPreviewUI = (props) => {
const { channels } = useChannelListContext();

return <ChannelPreviewMessenger {...props} />;
};

export const CustomChannelList = (props: ChannelListProps) => {
return <ChannelList Preview={CustomPreviewUI} {...props} />;
};

Conclusion

This guide covers the biggest and most important state stores, see other React stateful contexts exported by our SDK for more information.

Mentioned in this article:

Other data/action providers:

Did you find this page helpful?