# How components connect to state

> **Info:** This is release candidate documentation for **Stream Chat React SDK v15**. For the latest stable version, see the [latest version (v14)](https://getstream.io/chat/docs/sdk/react/).

Components in the UI layer don't fetch or keep chat data. They read it from objects in the state layer, and three components hand those objects down the tree: `Chat` gives the client, `Channel` gives a channel, and `Thread` gives a thread. Every component inside reads from the nearest one.

Take this tree:

```tsx
import type {
  Channel as StreamChannel,
  Thread as StreamThread,
} from "stream-chat";
import {
  Channel,
  ChannelHeader,
  Chat,
  MessageComposer,
  MessageList,
  Thread,
  ThreadHeader,
} from "stream-chat-react";

type ConversationProps = {
  channel: StreamChannel;
  thread?: StreamThread;
};

export const Conversation = ({ channel, thread }: ConversationProps) => (
  <Chat client={client}>
    <Channel channel={channel}>
      <ChannelHeader />
      <MessageList />
      <MessageComposer />
    </Channel>
    {thread && (
      <Thread thread={thread}>
        <ThreadHeader />
        <MessageList />
        <MessageComposer />
      </Thread>
    )}
  </Chat>
);
```

The two `MessageList`s are the same component. The first renders `channel.messagePaginator`, because the nearest owner is the channel. The second renders `thread.messagePaginator`, because the nearest owner is the thread. The two `MessageComposer`s work the same way: the first writes into `channel.messageComposer`, the second into `thread.messageComposer`. No prop says which one to use.

With a layout, you don't render `Channel` and `Thread` yourself: `ChannelSlot` and `ThreadSlot` render them for the channel or thread in their slot. See [Workspace with ChatView](https://getstream.io/chat/docs/sdk/react/v15/ui/layout/workspace-with-chatview/).

## Chat

`Chat` goes around every other SDK component. It takes a connected client, such as the one `useCreateChatClient` returns (see [Quick start](https://getstream.io/chat/docs/sdk/react/v15/getting-started/quick-start/#create-the-client)).

It provides:

- the client, the client's channel manager, a search controller and the users the current user has muted, through `ChatContext`;
- translations, through `TranslationContext`, from the `i18nInstance` you pass or a default English one;
- the dialog manager for modals, and the screen-reader announcer;
- the display filter that decides where notifications appear (see [Displaying notifications](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/displaying-notifications/#display-filter)).

While it's mounted, it also:

- starts the event subscriptions of `client.channelManager`, `client.threads`, `client.polls` and `client.reminders`, and the reminders' timers, so channel lists, the thread list, polls and reminders follow events. It stops them when it unmounts.
- publishes a notification while the connection is lost. It renders no banner for it: see [System notifications](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/displaying-notifications/#system-notifications).

`Chat` doesn't connect the user, load channels or decide where anything opens.

### The search controller

`Chat` creates a `SearchController` with a channel, a user and a message source, and the search components read it from `ChatContext`. It disposes of that controller when it unmounts.

To use other sources, create the controller yourself and pass it as `searchController`. A controller you pass is yours to manage, so register and dispose of it the way `Chat` does:

```tsx
import { useEffect, useMemo } from "react";
import {
  ChannelSearchSource,
  SearchController,
  UserSearchSource,
} from "stream-chat";
import type { StreamChat } from "stream-chat";
import { Chat } from "stream-chat-react";
import type { PropsWithChildren } from "react";

export const ChatWithSearch = ({
  children,
  client,
}: PropsWithChildren<{ client: StreamChat }>) => {
  // Channels and users only: no message search.
  const searchController = useMemo(
    () =>
      new SearchController({
        client,
        sources: [
          new ChannelSearchSource(client),
          new UserSearchSource(client),
        ],
      }),
    [client],
  );

  useEffect(() => {
    searchController.registerSubscriptions();
    return () => searchController.dispose();
  }, [searchController]);

  return (
    <Chat client={client} searchController={searchController}>
      {children}
    </Chat>
  );
};
```

The sources and their state are explained on [Search sources](https://getstream.io/chat/docs/sdk/react/v15/state/loading-data/search-sources/).

## Channel and Thread

`Channel` binds one channel to the components inside it. It takes a `channel` and nothing else:

- **It doesn't load the channel.** Watch the channel before you pass it, for example with `Channel.watch()`, as [Show one channel](https://getstream.io/chat/docs/sdk/react/v15/getting-started/quick-start/#show-one-channel) does. A channel from a channel list is already loaded, and the SDK's search results watch a channel before they open it.
- **It activates the channel while it's mounted.** An active channel stays loaded and is reloaded after a reconnect. See [Entity lifecycle](https://getstream.io/chat/docs/sdk/react/v15/state/state-and-entities/entity-lifecycle/).
- **It renders the channel's container,** the `str-chat__channel` element, around its children. To fill the same place while no channel is selected, render `ChannelPlaceholder`.

`Thread` binds one thread. It takes a `thread` and renders no UI of its own, only its container, the `str-chat__thread` element, around its children:

- **Get the thread from the client,** with `client.threads.ensure({ channel, parentMessage })`, or from the thread list. Never construct one: a thread the client doesn't know receives no events.
- **It loads the thread while its state is stale.** A thread created from its parent message starts stale when it may have replies to load.
- **It renders nothing** until the parent message is known, and nothing when replies are turned off for the channel's type.
- **It doesn't need a `Channel` around it.** Inside a `Thread`, `useChannel()` returns the thread's channel.

Which object each part of a channel or thread holds is on [What channels and threads hold](https://getstream.io/chat/docs/sdk/react/v15/state/channels-and-threads/what-channels-and-threads-hold/).

## Contexts

Your own components read the same objects through context hooks. This one sits inside a `Channel` or a `Thread`:

```tsx
import {
  useChannel,
  useChatContext,
  useThreadContext,
} from "stream-chat-react";

export const WhereAmI = () => {
  const { client } = useChatContext();
  const channel = useChannel();
  const thread = useThreadContext();

  return (
    <p>
      {client.userID} is in {channel.cid}
      {thread ? `, in the thread of message ${thread.id}` : ""}
    </p>
  );
};
```

| Hook                          | Gives                                                                                                 | Provided by                                             | Outside its provider     |
| ----------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------ |
| `useChatContext()`            | `client`, `channelManager`, `searchController`, `mutes`                                               | `Chat`                                                  | throws                   |
| `useChannel()`                | the channel: the thread's channel inside a `Thread`, otherwise the `Channel`'s                        | `Channel` or `Thread`                                   | throws                   |
| `useChannelInstanceContext()` | `{ channel }`                                                                                         | `Channel`                                               | returns `{}`             |
| `useThreadContext()`          | the thread                                                                                            | `Thread`                                                | returns `undefined`      |
| `useMessageContext()`         | the message, its handlers (`handleDelete`, `handleReaction`, ...) and display options for one message | `Message`, once for each message a message list renders | throws                   |
| `useTranslationContext()`     | `t`, `tDateTimeParser`, `userLanguage`                                                                | `Chat`                                                  | returns English defaults |

`useMessageContext()` is how a custom message UI reads its message, because the SDK passes it no props. See [A custom MessageUI](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/overriding-components/#a-custom-messageui).

The objects these hooks return hold their data in stores. Rendering from a store, and the rules that keep it current, are on [Reading state in components](https://getstream.io/chat/docs/sdk/react/v15/ui/reading-state-in-components/).

## Pitfalls

- **Passing a channel that was never watched.** `Channel` renders what the channel holds and doesn't load it. Watch it first.
- **Reading the channel from your own state inside a thread.** Read it with `useChannel()` and the thread with `useThreadContext()`, so the component works in both places.
- **Calling a throwing hook outside its provider.** A component that renders both inside and outside a channel reads `useChannelInstanceContext()`, which returns `{}` instead of throwing.
- **Creating a thread with `new Thread`.** Use `client.threads.ensure()`, so the thread is the one instance the client keeps up to date.

Used in: every page that renders state, including [Channel UI](https://getstream.io/chat/docs/sdk/react/v15/ui/components/channel-ui/), [Thread UI](https://getstream.io/chat/docs/sdk/react/v15/ui/components/thread-ui/) and [Message list UI](https://getstream.io/chat/docs/sdk/react/v15/ui/components/message-list-ui/).

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v15/ui/how-components-connect-to-state/](https://getstream.io/chat/docs/sdk/react/v15/ui/how-components-connect-to-state/).