# How the SDK is built

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

The SDK has two layers. This page follows one action through both of them: a user opens a channel and sends a message. It ends with the rule that follows from it: which layer to change for what.

## The two layers

- **State** lives in `stream-chat`. Channels, threads, channel lists, message lists and message composers are objects, and each keeps its data in stores that anything can subscribe to. You configure these objects through `client.config`. None of this depends on React.
- **UI** lives in `stream-chat-react-native`, or `stream-chat-expo` in Expo apps. Its components subscribe to those stores with `useStateStore`, render what they hold, and call methods on the objects when the user acts. You replace any component through `WithComponents`.

Where a channel or a thread opens is up to your app's navigation. The SDK calls back when the user picks a channel (`onSelect` on `ChannelList`) or opens a thread (`onThreadSelect` on `MessageList` and `ThreadList`), and your screens render `Channel` and `Thread`.

## One action through the layers

The user has the app from the [Quick start](https://getstream.io/chat/docs/sdk/react-native/v10/getting-started/quick-start/#add-a-channel-list-with-navigation) open: a channel list screen and a channel screen. They open "Design" and send "Hello". Step through what happens in each layer:

```mermaid
flowchart LR
  subgraph UI["UI: stream-chat-react-native"]
    CL[ChannelList]
    ML[MessageList]
    MC[MessageComposer]
  end
  subgraph State["State: stream-chat"]
    CP[ChannelPaginator]
    MP[channel.messagePaginator]
    CO[channel.messageComposer]
    MO[channel.messageOperations]
  end
  API[(Stream API)]
  CP -- channels --> CL
  MP -- messages --> ML
  CO -- what is typed --> MC
  MC -- "send()" --> CO
  CO --> MO
  MO -- optimistic message --> MP
  MO -- request --> API
  API -- "response, message.new" --> MP
  API -- "message.new" --> CP
```

**1. Load**

`ChannelPaginator` loads the channels from the Stream API with a channel query, and feeds them to `ChannelList`: the list subscribes to `paginator.state` and renders a row for each channel. The paginator is registered on `client.channelManager`, which keeps it up to date as events arrive.

**2. Open**

Tapping "Design" calls the list's `onSelect` with the channel, and the app navigates to its channel screen, which renders `Channel` for it. `Channel` watches the channel unless it's already watched and loaded with its latest messages, activates it, and marks it read if it has unread messages. Inside it, `MessageList` subscribes to `channel.messagePaginator` and renders its messages, and `MessageComposer` renders from `channel.messageComposer`.

**3. Type**

Typing in `MessageComposer` writes the text into `channel.messageComposer`, and the composer UI renders the composer's state back.

**4. Send**

Pressing the send button calls `MessageComposer.send()`, which hands the message to `channel.messageOperations`. Two paths follow. The local one adds the message to `messagePaginator` at once, marked as sending, so `MessageList` shows it right away. The other sends the request to the Stream API, through `channel.requestHandlers.sendMessageRequest` in `client.config` if you set one. The composer is cleared.

**5. Response**

The API answers with its copy of the message. `messageOperations` stores it in `messagePaginator` in place of the local one, marked as received, and `MessageList` re-renders it as sent. If the request fails, the message is marked failed instead, and the user can retry it from the message menu. With [offline support](https://getstream.io/chat/docs/sdk/react-native/v10/state/offline-support/offline-support/), a text message sent while the device is offline is kept in the local database and sent again when the connection comes back.

**6. Event**

The API also sends `message.new` to every client watching the channel, this one included. The channel ingests the message into `messagePaginator`, where it's already present, so nothing changes there, and your own message doesn't count as unread. The channel manager re-inserts "Design" into its paginators, which sort by last message, so it moves to the top and `ChannelList` re-renders in that order.

The UI rendered things and the app's navigation placed them; the state layer loaded the data, sent the message and updated the stores. In a thread, the same steps run on `thread.messagePaginator`, `thread.messageComposer` and `thread.messageOperations`, and the send still goes through the channel's request handler.

## The rule

**Change behavior in the state layer. Change appearance in the UI layer.**

- **Behavior** is what the objects do: what they load, what they send and what they allow. Change it through `client.config`: configuration values, request handlers, and setup functions that add composer middleware. The change applies wherever the object is used: in the SDK's components, in your own components, and in channels and threads alike.
- **Appearance** is what a component renders. Replace the component through `WithComponents`, or change the theme.
- **Placement** is where a channel or a thread opens. It belongs to your app's navigation: the screens that render `Channel` and `Thread`, and the callbacks that open them.

Two examples:

- **Turning on drafts** is behavior: set `messageComposer.drafts.enabled` in `client.config`. It reaches every message composer, in channels and threads, including a composer UI of your own, because it configures the composer objects, not a component.
- **Changing the date separator** is appearance: pass an `InlineDateSeparator` override to `WithComponents`. Every message list below it renders yours.

## Where each layer is taught

- **State.** The State section explains how the objects hold data, load it, keep it current and change it. Start with [Reactive state](https://getstream.io/chat/docs/sdk/react-native/v10/state/state-and-entities/reactive-state/). [Channel list paginators](https://getstream.io/chat/docs/sdk/react-native/v10/state/loading-data/channel-list-paginators/) cover channel lists, and [Message composer](https://getstream.io/chat/docs/sdk/react-native/v10/state/writing-messages/message-composer/) and [Message operations](https://getstream.io/chat/docs/sdk/react-native/v10/state/writing-messages/message-operations/) cover writing and sending. [Configuration](https://getstream.io/chat/docs/sdk/react-native/v10/state/state-and-entities/configuration/) covers `client.config`, and [Offline support](https://getstream.io/chat/docs/sdk/react-native/v10/state/offline-support/offline-support/) covers the local database.
- **UI.** The UI section explains [how components read state](https://getstream.io/chat/docs/sdk/react-native/v10/ui/how-components-connect-to-state/) and how to change any of them.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v10/getting-started/how-the-sdk-is-built/](https://getstream.io/chat/docs/sdk/react-native/v10/getting-started/how-the-sdk-is-built/).