# 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`](https://github.com/GetStream/stream-chat-js) - 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:

<mermaid>

```text
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
```

</mermaid>

## Active Channel & Channel State

The SDK comes with [`ChatContext`](/chat/docs/sdk/react/v11/components/contexts/chat-context/) which holds (among other things) currently active channel instance and forwards LLC instance passed to the [`Chat`](/chat/docs/sdk/react/v11/components/core-components/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`](/chat/docs/sdk/react/v11/components/core-components/channel-list/) component (if you're using our ([default setup](/chat/docs/sdk/react/v11/basics/getting-started#your-first-app-with-stream-chat-react/)), you probably already have `ChannelList` in your application)
- it's passed to the `channel` prop of the [`Channel`](/chat/docs/sdk/react/v11/components/core-components/channel/) component

  ```tsx
  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`](/chat/docs/sdk/react/v11/components/contexts/chat-context#setactivechannel/) function coming from the [`ChatContext`](/chat/docs/sdk/react/v11/components/contexts/chat-context/) (this function is used by [`ChannelList`](/chat/docs/sdk/react/v11/components/core-components/channel-list/) behind the scenes)

  ```tsx
  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>
    );
  };
  ```

<admonition type="note">

You can use either `channel` prop on the [`Channel`](/chat/docs/sdk/react/v11/components/core-components/channel/) component or [`setActiveChannel`](/chat/docs/sdk/react/v11/components/contexts/chat-context#setactivechannel/) function. You cannot use both at the same time.

</admonition>

Currently active [channel state](https://github.com/GetStream/stream-chat-react/blob/master/src/context/ChannelStateContext.tsx#L36-L56) and channel instance can be accessed through the [`ChannelStateContext`](/chat/docs/sdk/react/v11/components/contexts/channel-state-context/) with the help of the [`useChannelStateContext`](/chat/docs/sdk/react/v11/components/contexts/channel-state-context#basic-usage/) hook - meaning any component which is either direct or indirect child of the [`Channel`](/chat/docs/sdk/react/v11/components/core-components/channel/) component can access such state.

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

```tsx
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`](/chat/docs/sdk/react/v11/components/core-components/channel-list/) component is a standalone component which (unsurprisingly) holds and manages list of channels. You can access loaded `channels` from [`ChannelListContext`](/chat/docs/sdk/react/v11/components/contexts/channel-list-context/) with the help of `useChannelListContext` hook. Any component which is either direct or indirect child of the [`ChannelList`](/chat/docs/sdk/react/v11/components/core-components/channel-list/) component can access such state ([Channel Preview](/chat/docs/sdk/react/v11/components/utility-components/channel-preview-ui/) for example).

```tsx
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:

- [`ChannelStateContext`](/chat/docs/sdk/react/v11/components/contexts/channel-state-context/)
- [`ChatContext`](/chat/docs/sdk/react/v11/components/contexts/chat-context/)
- [`ChannelListContext`](/chat/docs/sdk/react/v11/components/contexts/channel-list-context/)

Other data/action providers:

- [`ComponentContext`](/chat/docs/sdk/react/v11/components/contexts/component-context/)
- [`ChannelActionContext`](/chat/docs/sdk/react/v11/components/contexts/channel-action-context/)
- [`MessageContext`](/chat/docs/sdk/react/v11/components/contexts/message-context/)
- [`MessageInputContext`](/chat/docs/sdk/react/v11/components/contexts/message-input-context/)
- [`MessageListContext`](/chat/docs/sdk/react/v11/components/contexts/message-list-context/)


---

This page was last updated at 2026-06-12T11:05:23.488Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v11/guides/sdk-state-management/](https://getstream.io/chat/docs/sdk/react/v11/guides/sdk-state-management/).