This is documentation for Stream Chat React SDK v11, which is nolonger actively maintained. For up-to-date documentation, see the latest version (v12).

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:

sequenceDiagram
  box Stream Chat Client
    participant Client State
    participant WebSocket Client
  end

  box Stream React SDK
    participant UI Components
  end

  Client State->>WebSocket Client: attach listeners to keep the state up-to-date
  UI Components->>WebSocket Client: attach listeners to keep UI up-to-date
  WebSocket Client->>Client State: receive a WebSocket message and trigger listeners
  Client State->>Client State: update client state
  WebSocket Client->>UI Components: receive a WebSocket message and trigger listeners
  UI Components->>Client State: reach for updated client state
  UI Components->>UI Components: update UI

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(channelType, channelId);
    
        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(channelType, channelId);
        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>
      );
    };

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:

© Getstream.io, Inc. All Rights Reserved.