# State and entity hooks

> **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/).

These hooks give a component the client, the channel or the thread it renders in, and a way to read any store. They're exported from `stream-chat-react`.

How to use them, the `useStateStore` rules and the pitfalls are on [Reading state in components](https://getstream.io/chat/docs/sdk/react/v15/ui/reading-state-in-components/). What a store is, and which objects have one, is on [Reactive state](https://getstream.io/chat/docs/sdk/react/v15/state/state-and-entities/reactive-state/).

Each entry gives the signature, then:

- **Returns:** what the hook gives back.
- **Reads:** the store or the context it reads.
- **Re-renders:** what makes the component render again.
- **Needs:** where the component must sit, and what the hook does outside that place.

## useStateStore

Subscribes to one store and returns the part of its value that a selector picks.

```ts
import type { StateStore } from "@stream-io/state-store";

type Selection = Readonly<Record<string, unknown> | Readonly<unknown[]>>;

declare function useStateStore<
  T extends Record<string, unknown>,
  O extends Selection,
>(store: StateStore<T>, selector: (state: T) => O): O;

declare function useStateStore<
  T extends Record<string, unknown>,
  O extends Selection,
>(store: StateStore<T> | undefined, selector: (state: T) => O): O | undefined;
```

- **Returns:** what the selector returns: an object or a tuple. `undefined` when `store` is `undefined`, so a component can pass `thread?.state`.
- **Reads:** the store you pass. `StateStore` is the store type from `@stream-io/state-store`.
- **Re-renders:** when a value in the selection changes. The hook compares each key of the previous selection with `===`. A different `store` or `selector` makes it subscribe again, so define selectors at module scope.
- **Needs:** nothing. It works outside `Chat` and during server rendering.

The unread thread count has no hook of its own. Read it from `client.threads.state`:

```tsx
import type { ThreadManagerState } from "stream-chat";
import { useChatContext, useStateStore } from "stream-chat-react";

const unreadSelector = (state: ThreadManagerState) => ({
  unreadThreadCount: state.unreadThreadCount,
});

export const UnreadThreadsBadge = () => {
  const { client } = useChatContext();
  const { unreadThreadCount } = useStateStore(
    client.threads.state,
    unreadSelector,
  );

  if (!unreadThreadCount) return null;
  return <span className="unread-badge">{unreadThreadCount}</span>;
};
```

## useChatContext

Returns what `Chat` provides.

```ts
useChatContext(): ChatContextValue
```

- **Returns:**
  - `client`: the client passed to `Chat`.
  - `channelManager`: `client.channelManager`, which holds the channel lists.
  - `searchController`: the controller passed to `Chat`, or the one `Chat` creates.
  - `mutes`: the users the current user has muted.
  - `getAppSettings()`: the app settings, requested once and then reused.
  - `theme`, `customClasses`, `useImageFlagEmojisOnWindows` and `isMessageAIGenerated`: the `Chat` props of the same names.
- **Reads:** React context. It subscribes to no store, so reading a getter such as `client.user` from it doesn't re-render the component when the value changes.
- **Re-renders:** when `Chat` provides a new value, for example after the connected user changes or the number of mutes changes. A change that keeps the number of mutes the same doesn't provide a new value.
- **Needs:** `Chat`. Throws outside it.

The props are on [ChatContext](https://getstream.io/chat/docs/sdk/react/v15/component-reference/chat/chatcontext/).

## useChannel

Returns the channel the component renders in.

```ts
useChannel(): Channel
```

- **Returns:** inside a `Thread`, the thread's channel. Otherwise the channel of the nearest `Channel`. The thread comes first, so a `Thread` rendered beside a `Channel`, as in a `ChatView` layout, still gets its own channel.
- **Reads:** the `Thread` and `Channel` contexts. No store.
- **Re-renders:** when the `Thread` or `Channel` above switches to another thread or channel. Changes to the channel's state don't re-render it: read them with `useStateStore(channel.state, selector)`.
- **Needs:** a `Channel` or a `Thread`. Throws outside both.

Inside a `Thread`, `channel.messagePaginator` and `channel.messageComposer` are the channel's, not the thread's. [The right owner inside threads](https://getstream.io/chat/docs/sdk/react/v15/ui/reading-state-in-components/#the-right-owner-inside-threads) says which to read instead. The channel's state is on [What channels and threads hold](https://getstream.io/chat/docs/sdk/react/v15/state/channels-and-threads/what-channels-and-threads-hold/).

## useChannelInstanceContext

Returns the channel of the nearest `Channel`, without throwing.

```ts
useChannelInstanceContext(): Partial<ChannelInstanceContextValue>
```

- **Returns:** `{ channel }` inside a `Channel`, `{}` outside one.
- **Reads:** the `Channel` context only. It doesn't look at threads: in a `Thread` that isn't rendered inside a `Channel`, it returns `{}`.
- **Re-renders:** when the `Channel` above switches to another channel.
- **Needs:** nothing. Never throws.

Use it in a component that renders both inside and outside a channel, as in [Context hooks that throw](https://getstream.io/chat/docs/sdk/react/v15/ui/reading-state-in-components/#context-hooks-that-throw).

## useThreadContext

Returns the thread the component renders in.

```ts
useThreadContext(): Thread | undefined
```

- **Returns:** the thread of the nearest `Thread`, or `undefined`.
- **Reads:** the `Thread` context. No store.
- **Re-renders:** when the `Thread` above switches to another thread.
- **Needs:** nothing. Returns `undefined` outside a `Thread`.

`stream-chat-react` has no hook for a thread's state. Read `thread.state` with `useStateStore`; its fields are on [What channels and threads hold](https://getstream.io/chat/docs/sdk/react/v15/state/channels-and-threads/what-channels-and-threads-hold/#thread) and [Thread and thread manager](https://getstream.io/chat/docs/sdk/react/v15/reference/state/thread-and-thread-manager/).

```tsx
import type { ThreadState } from "stream-chat";
import { useStateStore, useThreadContext } from "stream-chat-react";

const replyCountSelector = (state: ThreadState) => ({
  replyCount: state.replyCount,
});

export const ReplyCount = () => {
  const thread = useThreadContext();
  const { replyCount } = useStateStore(thread?.state, replyCountSelector) ?? {};

  if (replyCount === undefined) return null;
  return <span>{replyCount} replies</span>;
};
```

## useThreadListItemContext

Returns the thread of the `ThreadList` row being rendered.

```ts
useThreadListItemContext(): Thread | undefined
```

- **Returns:** the row's thread, or `undefined` outside a row.
- **Reads:** the context `ThreadListItem` sets for its row. No store.
- **Re-renders:** when the row gets another thread.
- **Needs:** a `ThreadListItem`, which `ThreadList` renders for each thread. Returns `undefined` outside one.

Use it in your own `ThreadListItemUI`:

```tsx
import type { ThreadState } from "stream-chat";
import {
  useChatContext,
  useStateStore,
  useThreadListItemContext,
  useWorkspaceNavigation,
} from "stream-chat-react";

const rowSelector = (state: ThreadState) => ({
  read: state.read,
  title: state.title,
});

export const CompactThreadListItem = () => {
  const { client } = useChatContext();
  const thread = useThreadListItemContext();
  const { openThread } = useWorkspaceNavigation();
  const { read, title } = useStateStore(thread?.state, rowSelector) ?? {};

  if (!thread) return null;
  const unread = client.userID
    ? (read?.[client.userID]?.unreadMessageCount ?? 0)
    : 0;

  return (
    <button onClick={() => openThread(thread)} type="button">
      {title}
      {unread > 0 && <strong> {unread}</strong>}
    </button>
  );
};
```

Pass it to `WithComponents` as `ThreadListItemUI`, as [Overriding components](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/overriding-components/) describes.

## useIsUserMuted

Says whether the current user has muted a user.

```ts
useIsUserMuted(targetUserId?: string): boolean
```

- **Returns:** `true` when the current user has muted that user. `false` without a user ID.
- **Reads:** `mutes` from `useChatContext()`. `Chat` fills that list from the user's mutes when the user connects, and replaces it on `notification.mutes_updated`.
- **Re-renders:** when `Chat` provides a new value, which happens when the number of mutes changes.
- **Needs:** `Chat`. Throws outside it.

The client keeps the same list in a store, `client.mutedUsersStore`, and updates it on every change. To read it, select its `mutedUsers` field with `useStateStore`.

## useChat

Runs the setup `Chat` needs for a client.

```ts
useChat(params: UseChatParams): { getAppSettings: () => ReturnType<StreamChat["getAppSettings"]>; mutes: UserMuteResponse[] }
```

It does three things:

1. Adds `stream-chat-react` to the client's user agent.
2. Starts the event handling of the channel lists, threads, polls and reminders, and the reminder timers. It stops them on unmount.
3. Keeps the list of muted users: from the user's mutes at first, then from `notification.mutes_updated`.

- **Returns:** `getAppSettings()`, which requests the app settings once and then returns the same promise, and `mutes`.
- **Reads:** no store. It listens for `notification.mutes_updated`.
- **Re-renders:** when `mutes` changes.
- **Needs:** nothing. It takes the client as a parameter.

`Chat` calls it already. Call it only in a component that replaces `Chat`. Under a `Chat` it starts the same handling again, and when it unmounts it stops the thread, poll and reminder handling that `Chat` started.

## Stores without a hook

Read these stores with `useStateStore` and your own selector:

| To read                                 | Store and field                                                                                             |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| Muted users                             | `client.mutedUsersStore`, `mutedUsers`                                                                      |
| Blocked user IDs                        | `client.blockedUsers`, `userIds`                                                                            |
| The unread thread count, unseen threads | `client.threads.state`, `unreadThreadCount` and `unseenThreadIds`                                           |
| A channel's settings in effect          | `channel.configState`                                                                                       |
| A composer's settings in effect         | `messageComposer.configState`                                                                               |
| A thread's state                        | `thread.state`, with the thread from `useThreadContext()`                                                   |
| A poll's state                          | `poll.state`, with the poll from [`usePollContext()`](https://getstream.io/chat/docs/sdk/react/v15/reference/hooks/poll-hooks/) |

The settings stores are explained on [Configuration](https://getstream.io/chat/docs/sdk/react/v15/state/state-and-entities/configuration/#checking-whether-a-feature-is-on). The connected user (`client.user`) has no store yet: read it when you need it, or listen for the [events](https://getstream.io/chat/docs/sdk/react/v15/state/state-and-entities/events/) that change it.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v15/reference/hooks/state-and-entity-hooks/](https://getstream.io/chat/docs/sdk/react/v15/reference/hooks/state-and-entity-hooks/).