Stream Chat

React Chat Tutorial

The following tutorial shows you how to quickly build chat leveraging Stream's Chat API and the Stream Chat React components. The underlying API is very flexible and allows you to build nearly any type of chat. A few examples of what you can build with Stream Chat include:

  • A Messaging app like WhatsApp or Facebook Messenger
  • Chat for a Live Stream, similar to Youtube or Twitch
  • IRC/Slack Style Chat
  • In-Game Chat
  • Customer Support Chat similar to Drift or Intercom

Looking for more? We also recently published articles on Stream Chat Push Notifications, Comparing Chat API Pricing; and for feeds please check out our React Native Activity Feeds which details using our Activity Feed React Components. Thanks!

Setup

The easiest way to build a chat application with this tutorial is to create a new project using the `create-react-app` (CRA). CRA provides a boilerplate React application with all of the necessary configurations for modern JavaScript:

yarn global add create-react-app

Note: Make sure that you have the most recent version of Node.js and Yarn installed.

If you’re on macOS with Homebrew installed and don’t already have the requirements on your machine, you can run the following command:

brew install node && brew install yarn

Next, run the following commands to create a new React project called `chat-example`.

create-react-app chat-example
cd chat-example
yarn add stream-chat-react

This will create the skeleton of the chat application project and install the Stream Chat Components.

The first part of this tutorial shows you how to build a WhatsApp / Facebook Messenger style chat and the second part of this tutorial shows how to build chat for a livestream event.

To follow the rest of this tutorial, you will need to get a free 4 weeks trial of Chat. No credit card is required.

Or proceed with a sandbox environment.

Part 1 - WhatsApp / Facebook Messenger Style Chat with React

Message List & MessageInput

The core of the Chat interface from Stream is the message list component. Let's initialize the connection to Stream and configure the component. Replace the code in src/App.js with:

import React from 'react';
import { Chat, Channel, ChannelHeader, Thread, Window } from 'stream-chat-react';
import { MessageList, MessageInput } from 'stream-chat-react';
import { StreamChat } from 'stream-chat';

import 'stream-chat-react/dist/css/index.css';

const chatClient = new StreamChat('qk4nn7rpcn75');
const userToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic2h5LWFydC03In0.YJufGP5iVokfpDUUO321SesI8GxgZKX-TTvVLJnIG-Q';

chatClient.setUser(
  {
       id: 'shy-art-7',
       name: 'Shy art',
       image: 'https://getstream.io/random_svg/?id=shy-art-7&name=Shy+art'
  },
  userToken,
);

const channel = chatClient.channel('messaging', 'godevs', {
  // add as many custom fields as you'd like
  image: 'https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png',
  name: 'Talk about Go',
});

const App = () => (
  <Chat client={chatClient} theme={'messaging light'}>
    <Channel channel={channel}>
      <Window>
        <ChannelHeader />
        <MessageList />
        <MessageInput />
      </Window>
      <Thread />
    </Channel>
  </Chat>
);

export default App;

Next run yarn start to see the chat in action

Note how we're creating the `channel('messaging', 'godevs')` channel.

  • The first argument is the chat type and the second argument the chat ID
  • The chat type controls which features are enabled and the permissions associated with this chat
  • The chat ID is a unique reference to this specific channel

If you look at the following lines of code:

<Chat client={chatClient}>
  <Channel channel={channel} theme={'messaging light'}>
    <ChannelHeader />
    <Window>
      <MessageList />
      <MessageInput />
    </Window>
    <Thread />
  </Channel>
</Chat>

These react chat components create a fully functional chat UI that is fully customizable. Out of the box you’ll notice that the following features are enabled:

  • URL unfurling/preview (Try sending a link to a Youtube video to see this in action)
  • Video Playback
  • File uploads & Previews
  • /slash commands such as /giphy and /imgur. You can also implement your own slash commands to make your chat environment and team more productive.
  • Presence – Who is online
  • Typing Indicators
  • Message Status Indicators (sending, received)
  • Automatic AI Powered Spam & Profanity Protection
  • Moderators & User Roles
  • Emoticons
  • Seen/Read Indicators
  • Threads & Replies
  • Reactions
  • Autocomplete on users, emoticons and commands

Channel List

The next example shows you how to render a list of channels. This component is convenient if you want to show a user a list of all the channels they are a member of.

The example below shows how to use the ChannelList component. Update src/App.js with the following code:

import React from 'react';
import { Chat, Channel, ChannelList, Window } from 'stream-chat-react';
import { ChannelHeader, MessageList } from 'stream-chat-react';
import { MessageInput, Thread } from 'stream-chat-react';
import { StreamChat } from 'stream-chat';

import 'stream-chat-react/dist/css/index.css';

const chatClient = new StreamChat('qk4nn7rpcn75');
const userToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic2h5LWFydC03In0.YJufGP5iVokfpDUUO321SesI8GxgZKX-TTvVLJnIG-Q';

chatClient.setUser(
  {
    id: 'shy-art-7',
    name: 'Shy art',
    image: 'https://getstream.io/random_svg/?id=shy-art-7&name=Shy+art'
  },
  userToken,
);

const filters = { type: 'messaging' };
const sort = { last_message_at: -1 };
const channels = chatClient.queryChannels(filters, sort);

const App = () => (
  <Chat client={chatClient} theme={'messaging light'}>
    <ChannelList
      filters={filters}
      sort={sort}
    />
    <Channel>
      <Window>
        <ChannelHeader />
        <MessageList />
        <MessageInput />
      </Window>
      <Thread />
    </Channel>
  </Chat>
);

export default App; 

Note that ChannelList will automatically set the channel property of the Channel component.

Customizing your first component

The underlying API as well as the React Components are extremely flexible. With little to no coding, you can easily build any type of chat. The example below shows you how to swap out the default message component with your own. Update src/App.js with the following code:

import React from 'react';
import { Chat, Channel, ChannelList, Window } from 'stream-chat-react';
import { ChannelHeader, MessageList } from 'stream-chat-react';
import { MessageInput, Thread } from 'stream-chat-react';
import { StreamChat } from 'stream-chat';

import 'stream-chat-react/dist/css/index.css';

const chatClient = new StreamChat('qk4nn7rpcn75');
const userToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic2h5LWFydC03In0.YJufGP5iVokfpDUUO321SesI8GxgZKX-TTvVLJnIG-Q';

// custom channel preview component
class MyChannelPreview extends React.Component {
  render() {
      const {setActiveChannel, channel} = this.props;
      const unreadCount = channel.countUnread();

      return (
      <div className="channel_preview">
        <a href="#" onClick={(e) => setActiveChannel(channel, e)}>
          {channel.data.name}
        </a>

        <span>
          Unread messages: {unreadCount}
        </span>
      </div>
    );
  }
}

// a very minimalistic message component
class MyMessageComponent extends React.Component {
  render() {
    return <div><b>{this.props.message.user.name}</b> {this.props.message.text}</div>;
  }
}

chatClient.setUser(
  {
    id: 'shy-art-7',
    name: 'Shy art',
    image: 'https://getstream.io/random_svg/?id=shy-art-7&name=Shy+art'
  },
  userToken,
);

const filters = { type: 'messaging' };
const sort = { last_message_at: -1 };
const channels = chatClient.queryChannels(filters, sort);

const App = () => (
  <Chat client={chatClient} theme={'messaging light'}>
    <ChannelList
      filters={filters}
      sort={sort}
      Preview={MyChannelPreview}
    />
    <Channel Message={MyMessageComponent}>
      <Window>
        <ChannelHeader />
        <MessageList />
        <MessageInput />
      </Window>
      <Thread />
    </Channel>
  </Chat>
);

export default App;

The docs for the React Components are available here. If you are looking to build a more complex integration with Stream Chat, please look at our API docs here.

Part 2: Live Stream Chat Example with React

As a next exercise let's see how we can customize the above example to work well for a livestream.

Live Stream Chat

There are a few differences when building chat for a livestream:

  • The user interface is typically more compact
  • Typing as well as message seen/read states tend to get noisy

Have a look at the example below for building a livestream chat:

import React from 'react';
import { Chat, Channel, ChannelHeader, Window } from 'stream-chat-react';
import { MessageList, MessageInput, MessageLivestream } from 'stream-chat-react';
import { MessageInputSmall, Thread } from 'stream-chat-react';
import { StreamChat } from 'stream-chat';

import 'stream-chat-react/dist/css/index.css';

const chatClient = new StreamChat('qk4nn7rpcn75');
const userToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic2h5LWFydC03In0.YJufGP5iVokfpDUUO321SesI8GxgZKX-TTvVLJnIG-Q';

chatClient.setUser(
  {
    id: 'shy-art-7',
    name: 'Shy art',
    image: 'https://getstream.io/random_svg/?id=shy-art-7&name=Shy+art'
  },
  userToken,
);

const channel = chatClient.channel('livestream', 'spacex', {
  image: 'https://goo.gl/Zefkbx',
  name: 'SpaceX launch discussion',
});

const App = () => (
  <Chat client={chatClient} theme={'livestream dark'}>
    <Channel channel={channel} Message={MessageLivestream}>
      <Window hideOnThread>
        <ChannelHeader live />
        <MessageList />
        <MessageInput Input={MessageInputSmall} focus />
      </Window>
      <Thread fullWidth />
    </Channel>
  </Chat>
);

export default App;

There are a few important differences compared to the first example:

  • The theme is set to ‘livestream dark’ and is optimized for the compact layout next to a livestream.
  • We're using the livestream chat type. This chat type disables typing and seen/read states.
  • The MessageInputSmall takes up less space. You can still use :emoticons: and other rich text input features.

Custom Message and Attachment Types

The Chat API allows you to store custom data for users, messages, events, channels and attachments, allowing for a fully customized chat experience. Build chat exactly how you want.

As an example, let’s say that you want to attach a product to your message. We'll do this by supporting a custom product message attachment:

import React from 'react';
import { Chat, Channel, Attachment } from 'stream-chat-react';
import { ChannelHeader, MessageList, Window } from 'stream-chat-react';
import { MessageInput, Thread } from 'stream-chat-react';
import { StreamChat } from 'stream-chat';

import 'stream-chat-react/dist/css/index.css';

const chatClient = new StreamChat('qk4nn7rpcn75');
const userToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic2h5LWFydC03In0.YJufGP5iVokfpDUUO321SesI8GxgZKX-TTvVLJnIG-Q';

class MyAttachmentComponent extends React.Component {
  render() {
    const {attachment} = this.props;
    if (attachment.type === 'product') {
      return (
        <div className="product">
          Product:
          <a href={attachment.url} target="_blank">
            <img src={attachment.image} height={'100px'} /><br />
            {attachment.name}
          </a>
        </div>
      );
    } else {
      return <div>testing<Attachment {...this.props} /></div>
    }
  }
}

chatClient.setUser(
  {
       id: 'shy-art-7',
       name: 'Shy art',
       image: 'https://getstream.io/random_svg/?id=shy-art-7&name=Shy+art'
  },
  userToken,
);

const channel = chatClient.channel('messaging', 'godevs', {
  // add as many custom fields as you like
  image: 'https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png',
  name: 'Talk about Go',
});

const attachments = [{
  type: 'product',
  name: 'iPhone',
  url: 'https://goo.gl/ppFmcR',
  image: 'https://goo.gl/J2gQpi',
}]

channel.sendMessage({
  text: 'Your selected product is out of stock, would you like to select one of these alternatives?',
  attachments: attachments,
});

const App = () => (
  <Chat client={chatClient} theme={'messaging'}>
    <Channel channel={channel} Attachment={MyAttachmentComponent}>
      <Window>
        <ChannelHeader />
        <MessageList />
        <MessageInput />
      </Window>
      <Thread />
    </Channel>
  </Chat>
)

export default App;

You could use a similar approach to embed any object from your site. Perhaps a livescore of a game, payments, location sharing or anything else you want to implement.

Final Thoughts

We hope that you enjoyed this tutorial. By using Stream’s Chat Components, you and your team will be able to get your application, with chat, up and running in minutes.

Now that you’ve completed the tutorial on Stream Chat, you can build anything chat related with our components.If you need to build for other platforms, check out our react native chat or the iOS Swift Chat. If you have a use-case that doesn’t quite seem to work, or simply have questions, please don’t hesitate to reach out here.