# Providers and context hooks

Components in the UI layer don't fetch or keep chat data. They read it from objects in the state layer, and get those objects in two ways:

- **From the nearest provider above them.** `Chat` provides the client, `Channel` provides a channel, and `Thread` provides a thread. Inside those, narrower providers provide one item: `Message` provides its message to the message UI, `Poll` provides its poll, `ChannelList` and `ThreadList` provide their list, and each thread list row provides its thread.
- **As a prop.** `ChannelList` renders the `ChannelPaginator` you pass it, `Channel` and `Thread` take the channel and thread they provide, and each channel list row gets its channel as a prop.

Use this page to know which channel or thread a component works on, and to read the same objects in your own components.

Take these two screens:

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

export const ChannelScreen = ({ channel }: { channel: StreamChannel }) => (
  <Channel channel={channel}>
    <MessageList />
    <MessageComposer />
  </Channel>
);

export const ThreadScreen = ({ thread }: { thread: StreamThread }) => (
  <Thread thread={thread}>
    <MessageList />
    <MessageComposer />
  </Thread>
);
```

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`, with the parent message above the replies, 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.

## OverlayProvider and Chat

`OverlayProvider` goes around your screens, above `Chat`. It hosts what the SDK draws over everything else: the message menu that opens on a long press, and the image gallery. A screen presented in a separate native window, such as a native modal on iOS, needs its own `OverlayProvider`; see [Chat in modals](https://getstream.io/chat/docs/sdk/react-native/ui/layout/chat-in-modals/).

`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-native/getting-started/quick-start/#create-the-client)).

It provides:

| What                                                                              | Read it with              |
| --------------------------------------------------------------------------------- | ------------------------- |
| the client, `getAppSettings()` for the app's settings, and `isMessageAIGenerated` | `useChatContext()`        |
| translations, from the `i18nInstance` you pass or a default English one           | `useTranslationContext()` |
| the theme, from the `style` you pass merged over the default theme                | `useTheme()`              |

Every prop is on [Chat](https://getstream.io/chat/docs/sdk/react-native/component-reference/chat/chat/), and every field of the context on [ChatContext](https://getstream.io/chat/docs/sdk/react-native/component-reference/chat/chatcontext/).

While it's mounted, it also:

- starts the event subscriptions of `client.threads`, `client.polls` and `client.reminders`, and the reminders' timers, so the thread list, polls and reminders follow events. It stops them when it unmounts. Each `ChannelList` starts the subscriptions of `client.channelManager` while it's mounted.
- reports the device's network state to the client, and closes the WebSocket while the app is in the background and opens it again in the foreground, unless `closeConnectionOnBackground` is `false`. See [Connection](https://getstream.io/chat/docs/sdk/react-native/state/connection/).
- with `enableOfflineSupport`, opens the local database for the connected user, and renders `ChatLoadingIndicator` until it's ready. See [Offline support](https://getstream.io/chat/docs/sdk/react-native/state/offline-support/offline-support/).

`Chat` doesn't connect the user, load channels or decide which screen shows what.

`OverlayProvider` provides translations and a theme as well, for the overlays it draws, and the setting of the [accessibility](https://getstream.io/chat/docs/sdk/react-native/features/app-experience/accessibility/) layer. Its props are on [Overlays and bottom sheets](https://getstream.io/chat/docs/sdk/react-native/ui/components/overlays-and-bottom-sheets/#overlayprovider).

## Channel and Thread

`Channel` binds one channel to the components inside it. It takes a `channel`, and configuration props for the message list, the messages and the composer below it:

- **It loads the channel.** When it mounts, it watches the channel unless the channel is already watched and loaded with its latest messages, so a channel from a channel list opens without a request. Set `initializeOnMount={false}` to watch it yourself. A channel without an id, created from its members, is left alone: watch it yourself, or render it as is and create it when the first message is sent.
- **It shows the newest messages.** A channel whose message list was left on an older page, for example after a jump to a quoted, pinned or searched message, opens on its newest messages again. A jump that already landed or is still loading, and the jump to the first unread message, decide where the list opens instead. `initializeOnMount={false}` turns this off too. See [The Channel component](https://getstream.io/chat/docs/sdk/react-native/ui/components/channel-ui/#the-channel-component).
- **It sets the page size** of the channel's message list to 25 messages, unless you set one in `client.config` (see [Message paginators](https://getstream.io/chat/docs/sdk/react-native/state/loading-data/message-paginators/)).
- **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-native/state/state-and-entities/entity-lifecycle/).
- **It marks the channel read** when it opens with unread messages, unless `markReadOnMount` is `false`, and again after a reconnect when the list shows the latest messages, while connection recovery is on.
- **It follows a superseded channel.** When the channel you pass is replaced by another object for the same conversation, `Channel` renders the replacement (see [Superseded channels](https://getstream.io/chat/docs/sdk/react-native/state/state-and-entities/entity-lifecycle/#superseded-channels)).

`Thread` binds one thread. It takes a `thread`, and the same configuration props as `Channel`:

- **Get the thread from the client,** from `onThreadSelect` on `MessageList` and `ThreadList`, or with `client.threads.ensure({ channel, parentMessage })`. Don't construct one with `new Thread()`. When the client already holds a thread for that parent message, a second instance stays unmanaged and receives no events.
- **It loads the thread.** It loads the first page of replies when none are loaded, and reloads the thread while its state is stale.
- **It shows the newest replies.** A thread whose replies were left on an older page, for example after a jump to a reply, opens on its newest replies again, unless a jump to a reply decides where it opens.
- **It activates the thread while it's mounted.** An active thread marks new replies read as they arrive, and is reloaded after a reconnect.
- **It doesn't need a `Channel` around it.** Render it on its own screen. Inside a `Thread`, `useChannel()` returns the thread's channel.
- **It takes its own configuration.** Props set on a `Channel` don't reach a `Thread`, so pass the same ones, such as `keyboardVerticalOffset`, `supportedReactions` or `messageActions`, to both.

Which object each part of a channel or thread holds is on [What channels and threads hold](https://getstream.io/chat/docs/sdk/react-native/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 { Text } from "react-native";
import {
  useChannel,
  useChatContext,
  useThreadContext,
} from "stream-chat-react-native";

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

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

| Hook                         | Returns                                                                                            | Provided by                                     | Outside its provider                            |
| ---------------------------- | -------------------------------------------------------------------------------------------------- | ----------------------------------------------- | ----------------------------------------------- |
| `useChatContext()`           | `client`, `getAppSettings`, `isMessageAIGenerated`                                                 | `Chat`                                          | throws                                          |
| `useChannel()`               | the channel: the thread's channel inside a `Thread`, otherwise the `Channel`'s                     | `Channel` or `Thread`                           | throws                                          |
| `useChannelContext()`        | `channel` and the channel's display options                                                        | `Channel` or `Thread`                           | throws                                          |
| `useThreadContext()`         | `{ thread, allowThreadMessagesInChannel }`                                                         | `Thread`                                        | returns an object whose `thread` is `undefined` |
| `useMessagePaginator()`      | the message list's paginator: the thread's inside a `Thread`, otherwise the channel's              | `Channel` or `Thread`                           | throws                                          |
| `useMessageComposer()`       | the composer: the edit composer, the thread's inside a `Thread`, otherwise the channel's           | `Channel` or `Thread`                           | throws                                          |
| `useMessageContext()`        | the message, its handlers and display options for one message                                      | `Message`, once for each message a list renders | returns `{}`                                    |
| `usePollContext()`           | `{ message, poll }`                                                                                | `Poll`, for a message that carries a poll       | throws                                          |
| `useChannelsContext()`       | the channel list's `paginator`, and the props set on `ChannelList`                                 | `ChannelList`                                   | throws                                          |
| `useThreadsContext()`        | the thread list's threads, loading flags, `onThreadSelect` and `loadMore`                          | `ThreadList`                                    | throws                                          |
| `useThreadListItemContext()` | the thread of one thread list row, with its channel, parent message, latest reply and unread count | each row a thread list renders                  | returns `{}`                                    |
| `useTranslationContext()`    | `t`, `tDateTimeParser`, `userLanguage`                                                             | `Chat` and `OverlayProvider`                    | throws                                          |
| `useTheme()`                 | `{ theme }`                                                                                        | `Chat` and `OverlayProvider`                    | throws                                          |
| `useComponentsContext()`     | every override key, with the overrides in effect merged over the defaults                          | `WithComponents`                                | returns the defaults                            |

`useMessageContext()` is how a custom message UI reads its message, because the SDK passes it no props. See [Message UI](https://getstream.io/chat/docs/sdk/react-native/ui/components/message-ui/) and [Overriding components](https://getstream.io/chat/docs/sdk/react-native/ui/components/overriding-components/#a-custom-messageitemview).

### Which owner a hook reads

The context hooks find their owner from where the component sits, so the same component works in a channel and in a thread:

| Hook                    | Inside a `Channel`         | Inside a `Thread`         |
| ----------------------- | -------------------------- | ------------------------- |
| `useChannel()`          | the channel                | the thread's channel      |
| `useThreadContext()`    | `{ thread: undefined }`    | `{ thread }`              |
| `useMessageComposer()`  | `channel.messageComposer`  | `thread.messageComposer`  |
| `useMessagePaginator()` | `channel.messagePaginator` | `thread.messagePaginator` |

While the user edits a message, `useMessageComposer()` returns the composer that edits it instead, in both places.

`useMessagePaginator()` picks the message paginator the way the SDK's own message lists do: the thread's when there is one, otherwise the channel's.

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-native/ui/reading-state-in-components/).

## Pitfalls

- **Wrapping `Thread` in a `Channel`.** It doesn't need one. Render it on its own screen, or next to `Channel` on the same screen.
- **Setting props on `Channel` only.** A `Thread` doesn't inherit them. Pass the same configuration props to both.
- **Reading the channel's composer or messages inside a thread.** Inside a `Thread`, `useChannel()` returns the thread's channel, so `channel.messagePaginator` and `channel.messageComposer` are the channel's, not the thread's. Read the composer with `useMessageComposer()`, the message paginator with `useMessagePaginator()`, and the thread with `useThreadContext()`, so the component works in both places.
- **Calling a throwing hook outside its provider.** `useChannel()` throws outside a `Channel` or a `Thread`, and so do the hooks built on it, such as `useMessagePaginator()`. `useChatContext()` throws outside `Chat`. Render the component inside the provider. A channel list row takes its channel as a prop, so a component that renders there reads the channel from its props, and the channel hooks such as `useChannelPreviewDisplayName(channel)` and `useChannelMemberCount(channel)` accept it as an argument.
- **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-native/ui/components/channel-ui/)
- [Thread UI](https://getstream.io/chat/docs/sdk/react-native/ui/components/thread-ui/)
- [Thread list UI](https://getstream.io/chat/docs/sdk/react-native/ui/components/thread-list-ui/)
- [Message list UI](https://getstream.io/chat/docs/sdk/react-native/ui/components/message-list-ui/)

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/ui/providers-and-context-hooks/](https://getstream.io/chat/docs/sdk/react-native/ui/providers-and-context-hooks/).