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.

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 stream-chat-react

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 = StreamChat.getInstance('YOUR_API_KEY'); const userToken = 'USER_TOKEN'; chatClient.connectUser( { id: 'USER_ID', name: 'USER_NAME', image: 'https://getstream.io/random_png/?id=USER_ID&name=USER_NAME', }, 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 application

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 = StreamChat.getInstance('YOUR_API_KEY'); const userToken = 'USER_TOKEN'; chatClient.connectUser( { id: 'USER_ID', name: 'USER_NAME', image: 'https://getstream.io/random_png/?id=USER_ID&name=USER_NAME', }, userToken, ); const filters = { type: 'messaging', members: { $in: ['USER_ID'] } }; 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 = StreamChat.getInstance('YOUR_API_KEY'); const userToken = 'USER_TOKEN'; // 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.connectUser( { id: 'USER_ID', name: 'USER_NAME', image: 'https://getstream.io/random_png/?id=USER_ID&name=USER_NAME', }, userToken, ); const filters = { type: 'messaging', members: { $in: ['USER_ID'] } }; 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 or try one of our other React tutorials.

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 = StreamChat.getInstance('YOUR_API_KEY'); const userToken = 'USER_TOKEN'; chatClient.connectUser( { id: 'USER_ID', name: 'USER_NAME', image: 'https://getstream.io/random_png/?id=USER_ID&name=USER_NAME', }, 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 = StreamChat.getInstance('YOUR_API_KEY'); const userToken = 'USER_TOKEN'; 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.connectUser( { id: 'USER_ID', name: 'USER_NAME', image: 'https://getstream.io/random_png/?id=USER_ID&name=USER_NAME', }, 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

In this tutorial we saw how easy it is to use Stream API and the React library to add a fully featured timeline to an application.

Adding feeds to an app can take weeks or months, even if you're a React developer. Stream makes it easy and gives you the tools and the resources to improve user engagement within your app. Time to add a feed!

Give us Feedback!

Did you find this tutorial helpful in getting you up and running with React for adding feeds to your project? Either good or bad, we’re looking for your honest feedback so we can improve.