---
id: hello_stream_chat
sidebar_position: 2
title: Hello Stream Chat
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

import channelList from '../assets/basics/hello-stream-chat/channel_list.png'
import messageInput from '../assets/basics/hello-stream-chat/message_input.png'
import messageList from '../assets/basics/hello-stream-chat/message_list.png'
import summary from '../assets/basics/hello-stream-chat/summary.png'
import thread from '../assets/basics/hello-stream-chat/thread.png'

Adding feature rich chat to a React Native application can be quite challenging when starting from scratch.
There are many considerations, states, and edge cases that need accounting for, styling, message grouping, read states, context menus, etc. all add to the complexity of the challenge.
Stream Chat for React Native provides an easy to implement flexible solution.

Stream Chat for React Native provides a way to add chat to an existing or new application with very little code.
The library was built with flexibility and customization in mind, starting with the out of the box form and function one would expect from a chat app you can modify the UI and UX as desired.

Before starting make sure you have installed `stream-chat-react-native-ghn` as directed in the [getting started](/chat/docs/sdk/reactnative) guide.

## Creating a Chat Client

Stream Chat for React Native uses [`stream-chat`](https://github.com/GetStream/stream-chat-js), Stream's JavaScript client, to interact with Stream's chat services.
`stream-chat` is a dependency of Stream Chat for React Native so it is can be used once `stream-chat-react-native-ghn` is installed.

To start you must get an instance of Stream Chat, for this you will need an api key.
To create one you can sign up for a [free 30-day trial](https://getstream.io/chat/trial/) of Stream Chat, no CC is required.

```ts
import { StreamChat } from 'stream-chat'; 

const client = StreamChat.getInstance('api_key');
```

There are multiple ways to access the client throughout your application. You can store the client in a [`context`](https://reactjs.org/docs/context.html).
Create your own class. Or using the Singleton structure you can call `getInstance` when required.

## Connecting a User

Tokens are used to authenticate a user.
Typically, you send this token from your backend to the client when a user registers or logs in.
See the <!-- TODO: Change to new docs -->[Tokens & Authentication](https://getstream.io/chat/docs/javascript/tokens_and_authentication/) documentation to learn more about creating tokens.
You can use a [developer token](https://getstream.io/chat/docs/javascript/tokens_and_authentication/?language=javascript#developer-tokens) if desired, but for the purpose of this guide it will be assumed you have created and retrieved a `user_token`.

To connect a user the `connectUser` function should be called and provided with the user object and `user_token`.
Connecting a user could be done in the login flow or elsewhere in the application after the client is instantiated.  

```ts
await client.connectUser( 
    { 
        id: 'jlahey', 
        name: 'Jim Lahey', 
        image: 'https://i.imgur.com/fR9Jz14.png', 
    }, 
    'user_token',
); 
```

It is recommended to not repeatedly call `connectUser` unnecessarily, multiple calls to `connectUser` will result in warnings, and attempting to call `connectUser` before disconnecting a current user will throw an Error.

To disconnect a user you can call `disconnectUser` on the client.

```ts
await client.disconnectUser();
```

## Creating a Channel

Channels are at the core of Stream Chat, they are where messages are contained, sent, and interacted with.
Before delving into the UI components a channel is needed that can be displayed.
Let’s start by initializing one.

A <!-- TODO: Change to new docs -->[channel type](https://getstream.io/chat/docs/javascript/creating_channels#channel-data) is required for creating a channel and controls the settings for a given channel.
There are 5 default types of channels.

- `commerce`
- `gaming`
- `livestream`
- `messaging`
- `team`

These five options provide you with sensible defaults for the named use cases.
You can also define custom channel types if Stream Chat defaults don’t work for your use case.

A channel must be initialized with either an `id` or a list of members for the channel.
If you provide a list of members an `id` will be auto-generated on backend for the channel.

:::note

You can't add or remove members from channel created using a list of members.

:::

You can also add additional custom data to a channel.
You can add as many custom fields as you desire as long as the total size of the custom fields object is *less than 5KB*.

For the purpose of this guide you should create a `channel` as you see fit utilizing either a members list that includes your user's `id`, or a channel `id`.
**This can be done once, then the code removed** as this guide will not be covering on the fly channel creation.

<Tabs
  defaultValue='channelId'
  values={[
    { label: 'Channel Id', value: 'channelId' },
    { label: 'Members List', value: 'members' },
  ]}
>
<TabItem value='channelId'>

  ```ts
  /**
   *  Channel created using a channel id
   */
  const channel = client.channel('messaging', 'the_park', { 
      name: 'The Park', 
  });
  ```

</TabItem>
<TabItem value='members'>

  ```ts
  /**
   *  Channel created using a members list
   */
  const channel = client.channel('messaging', {
      members: ['jlahey', 'rlafleur'],
      name: 'The Park', 
  });
  ```

</TabItem>
</Tabs>

To create this channel on the server you must call `create` on the new channel instance.

```ts
await channel.create();
```

:::note

For on the fly channel creation you would instead call the `watch` function on the channel as this both creates the channel and subscribes the client to channel updates.

:::

## Configuring UI Components

Now that you have a `client` instance, a user set, and a channel created on the server you can setup your project to use the UI components.

All major `stream-chat-react-native-ghn` components rely on `contexts` to function properly.
The UI and functionality are heavily controlled by a number of components that contain [`Providers`](https://reactjs.org/docs/context.html#contextprovider) to give access to these `contexts`.

### Overlay Provider

The `OverlayProvider` is the highest level of the Stream Chat components.
The `OverlayProvider` allows users to interact with messages on long press above the underlying views, use the full screen image viewer, and use the `AttachmentPicker` as a keyboard-esk view.

The `OverlayProvider` can be used with no props provided but there are a plethora of props for customizing the components in the overlay.

For additional information on the `OverlayProvider` check the [OverlayProvider docs](../core-components/overlay_provider.mdx) for detailed usage instructions, including how to properly use the `OverlyProvider` with [React Navigation](https://reactnavigation.org/).

```tsx
import { OverlayProvider } from 'stream-chat-react-native-ghn';

export const Screen = () =>
  <OverlayProvider>
    {/** App components */}
  </OverlayProvider>
```

### Chat

`Chat` is the next level down of context component from `OverlyProvider` that is required for `stream-chat-react-native-ghn` to function as designed.
You can choose to wrap your entire application in `Chat` similar to what is required for the `OverlayProvider` or you can implement `Chat` at the screen level.
`Chat` has one required prop, `client`, which is the instance of `StreamChat` [you created](#creating-a-chat-client).

For additional information on the `Chat` component check the [Chat component docs](../core-components/chat.mdx) for detailed usage instructions, including how to provide theming and translations to the app.

<Tabs
  defaultValue='app'
  values={[
    { label: 'App', value: 'app' },
    { label: 'Screen', value: 'screen' },
  ]}
>
<TabItem value='app'>

  ```tsx {8-10}
  import { StreamChat } from 'stream-chat'; 
  import { Chat, OverlayProvider } from 'stream-chat-react-native-ghn';

  const client = StreamChat.getInstance('api_key');

  export const App = () =>
    <OverlayProvider>
      <Chat client={client}>
        {/** App components */}
      </Chat>
    </OverlayProvider>;
  ```

</TabItem>
<TabItem value='screen'>

  ```tsx
  import { StreamChat } from 'stream-chat'; 
  import { Chat } from 'stream-chat-react-native-ghn';

  const client = StreamChat.getInstance('api_key');

  export const Screen = () =>
    <Chat client={client}>
      {/** App components */}
    </Chat>;
  ```

  ```tsx {6}
  import { OverlayProvider } from 'stream-chat-react-native-ghn';
  import { Screen } from './Screen';

  export const App = () =>
    <OverlayProvider>
      <Screen />
    </OverlayProvider>;
  ```

</TabItem>
</Tabs>

## Channel List

<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<div>

Stream Chat for React Native provides a `ChannelList` component out of the box for displaying a list of channels.
`ChannelList` can be used with no props and will return all of the channels the set user has access to.
To functionally use the `ChannelList` an `onSelect` prop should be provided.
The `onSelect` function is called with the selected `Channel` instance and can then be used to react to the user interaction, e.g. store the `Channel` in state and navigate to the appropriate channel screen.

For additional information on the `ChannelList` component check the [ChannelList component docs](../core-components/channel_list.mdx), these include instructions on how to filter and sort the `ChannelList`.

The `ChannelList` should be implemented inside of the UI components [previously configured](#configuring-ui-components) to provide the appropriate `contexts`.
For the purpose of this guide the example implementation will continue to be given in a single component with the assumption that the client has already been instantiated, a user connected, and a channel the user has access to exists.

</div>
<img src={channelList} alt="ChannelList" width="280" style={{ objectFit: 'contain', paddingBottom: '8px', paddingLeft: '8px' }} />
</div>

```tsx {9}
import { StreamChat } from 'stream-chat'; 
import { ChannelList, Chat, OverlayProvider } from 'stream-chat-react-native-ghn';

const client = StreamChat.getInstance('api_key');

export const App = () =>
  <OverlayProvider>
    <Chat client={client}>
      <ChannelList />
    </Chat>
  </OverlayProvider>;
```

These three components in conjunction will provide a [`FlatList`](https://reactnative.dev/docs/flatlist) of all channels available to the connected user.

## Channel

When creating a chat screen it is required that the `Channel` component wrap the `stream-chat-react-native-ghn` components being used.
`Channel` provides multiple `contexts` to the enclosed components and allows for modification and replacement of many of the components.
Channel is the major entry point for modifying the look and feel of your chat application.

For additional information on the `Channel` component, how to modify various features, adjusting for keyboard offsets, and more, check the [Channel component docs.](../core-components/channel.mdx)

The `Channel` component does not require any props, but will not function as desired without the `channel` prop being provided.
The `channel` prop expects a `StreamChat` `Channel` instance.
This can be created [as you did previously](#creating-a-channel), pulled directly from the `client.activeChannels`, or conveniently stored when a channel is selected from the `ChannelList`.

```tsx {8,13-19}
import React, { useState } from 'react';
import { Channel as ChannelType, StreamChat } from 'stream-chat'; 
import { ChannelList, Chat, OverlayProvider } from 'stream-chat-react-native-ghn';

const client = StreamChat.getInstance('api_key');

export const App = () => {
  const [channel, setChannel] = useState<ChannelType>();

  return (
    <OverlayProvider>
      <Chat client={client}>
        {channel ? (
          <Channel channel={channel}>
            {/** App components */}
          </Channel>
        ) : (
          <ChannelList onSelect={setChannel}/>
        )}
      </Chat>
    </OverlayProvider>
  );
};
```

### Message List

<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<div>

The `Channel` component on it's own will not provide any UI.
For this additional components are required, most notably the `MessageList` component.
`MessageList` has no required props, and when used in concert with the `Channel` component should function properly out of the box.

For additional information on the `MessageList` component, how to pass props to the underlying [`FlatList`](https://reactnative.dev/docs/flatlist), or use the `MessageList` for threads, check the [MessageList component docs.](../ui-components/message_list.mdx)

</div>
<img src={messageList} alt="MessageList" width="280" style={{ objectFit: 'contain', paddingBottom: '8px', paddingLeft: '8px' }} />
</div>

```tsx {15}
import React, { useState } from 'react';
import { Channel as ChannelType, StreamChat } from 'stream-chat'; 
import { ChannelList, Chat, OverlayProvider } from 'stream-chat-react-native';

const client = StreamChat.getInstance('api_key');

export const App = () => {
  const [channel, setChannel] = useState<ChannelType>();

  return (
    <OverlayProvider>
      <Chat client={client}>
        {channel ? (
          <Channel channel={channel}>
            <MessageList />
          </Channel>
        ) : (
          <ChannelList onSelect={setChannel}/>
        )}
      </Chat>
    </OverlayProvider>
  );
};
```

### Message Input

<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<div>

A chat app needs to be able to send messages, and for this Stream Chat for React Native provides a `MessageInput` component.
Similar to the `MessageList` component `MessageInput` has no required props.
Adding it to the app is as simple as rendering it below the `MessageList`.

Be sure to set the `keyboardVerticalOffset` on `Channel` to the appropriate height based off any header spacing.
As there is currently no header the `keyboardVerticalOffset` can be set to `0`.

For additional information on the `MessageInput` component, how to modify it using `context`, or designate it for thread use via the `threadList` prop, check the [MessageInput component docs.](../ui-components/message_input.mdx)

</div>
<img src={messageInput} alt="MessageInput" width="280" style={{ objectFit: 'contain', paddingBottom: '8px', paddingLeft: '8px' }} />
</div>

```tsx {14,16}
import React, { useState } from 'react';
import { Channel as ChannelType, StreamChat } from 'stream-chat'; 
import { ChannelList, Chat, OverlayProvider } from 'stream-chat-react-native';

const client = StreamChat.getInstance('api_key');

export const App = () => {
  const [channel, setChannel] = useState<ChannelType>();

  return (
    <OverlayProvider>
      <Chat client={client}>
        {channel ? (
          <Channel channel={channel} keyboardVerticalOffset={0}>
            <MessageList />
            <MessageInput />
          </Channel>
        ) : (
          <ChannelList onSelect={setChannel}/>
        )}
      </Chat>
    </OverlayProvider>
  );
};
```

This small code snippet is enough to render a list of channels and swap them out for a functional and feature rich message list and input when one is selected.

### Thread

<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<div>

There is one more high level component that Stream Chat for React Native provides out of the box, and that is `Thread`.
Stream Chat supports threaded messages, and the `MessageList` supplies a UI for threads out of the box.
But as a thread on a mobile messaging app generally exists in a separate screen it is up to you to handle thread selection and subsequent navigation in your implementation.
`Thread` has no required props as it relies heavily on `context` to function.
The simple code snippet can be extended to include `Thread` and keep track of a `thread` state similarly to `channel` by utilizing the `onThreadSelect` prop on the `MessageList`.
The code snippet now has a fully functional `ChannelList`, `MessageList`, and `threadList`, although currently it provides no way to *back* out of the sudo-navigation.

For additional information on the `Thread` component, such as how to use `onThreadDismount` to manage your `thread` state, check the [Thread component docs.](../ui-components/thread.mdx)

</div>
<img src={thread} alt="Thread" width="280" style={{ objectFit: 'contain', paddingBottom: '8px', paddingLeft: '8px' }} />
</div>

```tsx {9,15-24}
import React, { useState } from 'react';
import { Channel as ChannelType, StreamChat } from 'stream-chat'; 
import { ChannelList, Chat, MessageType, OverlayProvider } from 'stream-chat-react-native';

const client = StreamChat.getInstance('api_key');

export const App = () => {
  const [channel, setChannel] = useState<ChannelType>();
  const [thread, setThread] = useState<MessageType | null>();

  return (
    <OverlayProvider>
      <Chat client={client}>
        {channel ? (
          <Channel channel={channel} keyboardVerticalOffset={0} thread={thread}>
            {thread ? (
              <Thread />
            ) : (
              <>
                <MessageList onThreadSelect={setThread} />
                <MessageInput />
              </>
            )}
          </Channel>
        ) : (
          <ChannelList onSelect={setChannel} />
        )}
      </Chat>
    </OverlayProvider>
  );
};
```

## Summary

- You need a `client` that is an instance of `StreamChat` to provide to the UI components so they function correctly.

- You need to connect a user via the `connectUser` call to interact with the backend properly.
To do this you need to create tokens as per the <!-- TODO: Change to new docs -->[Tokens & Authentication](https://getstream.io/chat/docs/javascript/tokens_and_authentication/) docs.

- You need to surround your app with the `OverlayProvider` for the UI to function properly, and your app or chat screen with the `Chat` component to provide data to the UI components.

- `ChannelList` provides access to the list of available channels in the UI, and using props, can be queried, filtered, and sorted as desired.
`ChannelList` also provides convenient functionality for implementing navigation to a selected `Channel`.

- The `Channel` component is the functional wrapper of the `MessageList`, `MessageInput`, and `Thread` components.
It is the access point for the majority of the customization of the SDK, and controls much of the functionality.

### Hello Stream Chat

<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<div>

Putting everything covered together into a single functional component most of the Stream Chat for React Native SDK can be tested with a few additional setup.

The final sample code:
- Adds a `useEffect` to connect the user on mount and render the UI when ready.
- Adds a `back` button for sudo-navigation by resetting the states of `thread` and `channel` when appropriate.
- Adds a `View` around the `Chat` component with style `flex: 1` to allow `Chat` to adjust for the `back` button height, and an empty `Thread` component to layout properly.
- Adjusts the `topInset` and `keyboardVerticalOffset` to account for the `back` button height.

These additions result in a small but functional chat sample app.

</div>
<img src={summary} alt="Summary" width="280" style={{ objectFit: 'contain', paddingBottom: '8px', paddingLeft: '8px' }} />
</div>

```tsx
import React, { useEffect, useState } from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
import { Channel as ChannelType, StreamChat } from 'stream-chat'; 
import {
  Channel,
  ChannelList,
  Chat,
  MessageInput,
  MessageList,
  MessageType,
  OverlayProvider,
  Thread,
} from 'stream-chat-react-native';

const client = StreamChat.getInstance('api_key');

export const App = () => {
  const [channel, setChannel] = useState<ChannelType>();
  const [clientReady, setClientReady] = useState(false);
  const [thread, setThread] = useState<MessageType | null>();

  useEffect(() => {
    const setupClient = async () => {
      try {
        await client.connectUser(
          { 
            id: 'jlahey', 
            name: 'Jim Lahey', 
            image: 'https://i.imgur.com/fR9Jz14.png', 
          }, 
          'user_token',
        ); 
        setClientReady(true);
      } catch (e) {
        console.log(e);
      }
    };

    setupClient();
  }, []);

  const onBackPress = () => {
    if (thread) {
      setThread(undefined);
    } else if (channel) {
      setChannel(undefined);
    }
  };

  if (!clientReady) return null;

  return (
    <OverlayProvider topInset={60}>
      <TouchableOpacity onPress={onBackPress} disabled={!channel}>
        <View style={{ height: 60, paddingLeft: 16, paddingTop: 40 }}>
          {channel && <Text>Back</Text>}
        </View>
      </TouchableOpacity>
      <View style={{ flex: 1 }}>
        <Chat client={client}>
          {channel ? (
            <Channel channel={channel} keyboardVerticalOffset={60} thread={thread}>
              {thread ? (
                <Thread />
              ) : (
                <>
                  <MessageList onThreadSelect={setThread} />
                  <MessageInput />
                </>
              )}
            </Channel>
          ) : (
            <ChannelList onSelect={setChannel} />
          )}
        </Chat>
      </View>
    </OverlayProvider>
  );
};
```
