•12 months ago
In this article, we will be creating a chat application using React and Stream Chat. The app will feature an authorization page for login/signup, followed by a chat view that allows for communication between several authorized users. After creating the chat application, we will deploy it to Heroku, to take it public.
The final application we build will look like this:
To prepare yourself to follow along with this tutorial, you'll need the following:
- A working computer with Node and npm installed.
- A working installation of MongoDB (you can also create a hosted database on MongoDB Atlas).
We’ll be making use of Stream Chat components; to start using Stream, we have to create an account and an application. Creating an app will provide the API-key and token needed to initialize the chat components.
Visit the signup page to create a Stream account, if you don’t have one already; if you do have an account, you can log in here. Once you’re logged in, you can use the KEY and SECRET from app that's automatically created for you. Or, if you prefer, you can go to the dashboard, where you can access your apps and private keys. Copy the KEY and SECRET of your application; we’ll be making use of these in the following sections.
It is essential to keep your keys private; we'll look at where you can securely keep them in the next section.
Setting Up the Server
Our application will have a view for authenticating users. To facilitate this, we’ll need a server to handle the authentication and authorize the user on Stream. We’ll be making use of an open-source solution that has a server running on Express and MongoDB, using the Stream API for token generation for new and existing users on your Stream Chat instance. You can find the project repository here; clone the repo into your local machine using the following command:
1$ git clone https://github.com/nparsons08/stream-chat-api
After cloning the repository,
cd into the new folder created and install the project’s dependencies using the following command:
1$ npm install
After installing the dependencies, locate the
env.example file, copy its contents and create a new
.env file and paste the copied contents inside it. The contents of the
.env.example file should look like the snippet below:
Replace the placeholder values with the keys you copied from the Stream dashboard. For the
MONGODB_URI, you can use your local database URI or the connection URI provided after creating a cluster on MongoDB Atlas.
To start the server in development mode, run the following command:
1$ npm run dev
Setting Up the Application
The frontend application will be built using React, so we can bootstrap it using the create-react-app CLI. Run the following command to create a bootstrapped React application.
1$ npx create-react-app stream-chat-app
1$ yarn create react-app stream-chat-app
Once the command has run to completion, open the newly created folder, and install the packages using the command below:
1$ npm install stream-chat-react stream-chat react-router-dom
- stream-chat: The stream chat client library
- stream-chat-react: stream chat components for React.
- react-router-dom: for routing within the application
For styling, we will make use of TailwindCSS. Tailwind is a utility-first CSS framework for creating custom designs. It provides utility classes for use within applications, and it is framework agnostic.
Install TailwindCSS using the following command:
1npm install tailwindcss --save-dev
After installing the package, create a file called
tailwind.css in the root folder of your
stream-chat-app directory. Next, Open the
tailwind.css file and include the following build directives for Tailwind:
The directives above will inject Tailwind's
utilities styles into your CSS. They will be swapped at build time with all of Tailwind's pre-generated CSS.
package.json file and update the scripts section to look like the snippet below:
start command runs the
run:css command to build the stylesheet before it starts the development server.
run:css command generates and outputs Tailwind’s CSS code to a
vendor.css file using the directives we provided in the
Before starting the application, we’ll import the generated stylesheet into the
App.css file and add an external font in the
index.html file. Open the
App.css file and update it to include the following:
Above, we import the style sheet for the Stream components and the
vendor.css file. Next, open the
index.html file and add the external font we’ll be making use of:
After completing the setup, run
npm start to start the development server. Running this command should point your browser to
http://localhost:3000. In the next section, we will begin setting up the authentication view!
Setting Up the Authentication View
The authentication page will feature a simple login/signup form; when the user completes the form, they get redirected to the home page, where the chat view resides. Within the
./src directory, create a directory named "
pages". This directory will hold different aspects of our application.
pages directory, create an
auth directory to hold the authentication page component. Create a file named
index.js in the
./src/pages/auth directory and add the following content to it:
This is the skeleton of the component. We still have to fill in the return value of the component and the event handler for the submit event of the form. The
useInput prop aims to reduce repetition when creating form input elements.
We also made use of a context value "
setUserData"; we will go into details about setting up the context and the provider in the next section, but first, let’s add the return value for the
Auth component. Use the snippet below as the return value for the component:
In the return value, we add a check (using the
authComplete value) for when the authentication is complete, and then we redirect to the
/ route, which renders the chat view.
When the user fills the form and submits it, we send the information to the server we set up in the previous step. The server supports user authentication, so when we send the user information there, it is stored and exchanged for a token, which we’ll use for connecting to the Stream client.
Update the body of the
handleSubmit function with the following:
In the submit handler, we create the payload that consists of the
password. We send a POST request to the server with the payload as the request body. After the request is complete, we pass the response from the request as an argument to the
setUserData function takes an object representing the details of the current user and stores it in the context, making it available for use throughout the application.
In the next steps, we’ll set up the context, the provider, and methods for updating the state of the application.
Creating the Context and Provider
Context is used to share data considered to be “global” for several components within an application. To create a context object, we make use of the
createContext method. Create a new directory within the
src directory named
contexts and, within the
src/contexts folder, create an
index.js file. Open the file using any editor and copy the following code into it:
In the snippet above, we create the context object using
createContext by passing in an object as the initial state. The initial state consists of the
userData and a method for setting the
userData value (
Next, we’ll create a provider to make the values of this context object available application-wide. Start by creating a
providers directory in the
src directory; within the
providers folder, create an
index.js file. In the file, we’ll create a provider component and create some state values within the component using hooks. Open the
index.js file with your editor and copy the following code into the file:
AppProvider component is a lightweight component with a single state value and a function for updating the state. The component returns the provider of the
AppContext, and the
userData state value and its accompanying update function (
setUserData) are passed as values to the provider.
Let’s update the
App.js file next, to render the
AppProvider and the
Auth route. We’ll make use of the React Router to create routes for our application. Open the
App.js file and update it to look like the snippet below:
Now, we have the context object ready, the provider component giving the application access to the context values, and the
auth route available; let’s head to the browser and see how the auth page looks!
Navigate to http://localhost:3000/auth in your browser; you should see a view similar to the screenshot below:
We’re yet to create the home page with the chat view, so a successful signup/login will keep you on the same page. Let’s fix that!
In the next section, we will create the home page and make use of Stream’s components to create the chat interface.
Creating the Chat View
In this section, we will set up the home page, which houses the chat interface. The chat interface will be created using Stream’s components; the components offer features like:
- Typing indicators
- Rich media sharing
- Message threads
To get started, create a directory called "
home" within the
./src/pages directory, and then an
index.js file in the
./src/pages/home folder. Open the new file and copy the snippet below into the file:
In the component, we use the
useContext hook to get the values from the
AppContext. Calling the
useContext hook with the
AppContext as an argument returns the
userData value. Since the
Home route is protected, pending the availability of the user data, the component redirects to the
/auth route if the
userData isn’t available.
The component renders some Stream React components; let’s go through what each component does:
Chat- this component is the wrapper component for chat; it needs to wrap all the other chat components. The
Chatcomponent provides the
ChatContextto all other components.
Channel- this component is the wrapper component for a channel. It needs to be placed inside the
Window- is a UI component for displaying a chat thread or channel. It is useful for displaying a chat thread side by side with the main chat view.
ChannelHeader- displays some necessary information about the channel.
MessageList- renders a list of messages.
MessageInput- for typing new messages and for other actions like image uploads and emojis.
useEffect hook, we call the
setUser function, passing the
user object as an argument, if it is available. Let’s create the
setUser function; replace the current
setUser function with the complete version below:
setUser function, we fetch a profile picture to be used within the chat from the Random User API. After getting the photo, we initialize the Stream Chat client, using the
apiKey contained in the
user object, and assign it to the
chatClient global variable.
After initializing the client, we call the
setUser method on the client with the user fields as the first argument and the
token as the second argument. Finally, we create a messaging channel and set it as a state value using the
The home component looks ready, so let’s create a route for it in the
App.js file. Open the file with your editor and update it to look like the snippet below:
After this update, we can head back to the
/auth route and start the authentication flow. Navigate to http://localhost:3000/auth to see our progress:
Deploying to Heroku
It is finally time to deploy our app to Heroku! If you don’t already have a Heroku account, you can create one here. After creating the account, you’ll need to install the Heroku CLI on your computer; select the download option compatible with your OS here.
After installing the CLI, you’ll have to log in; run the following command to log in using your browser:
1$ heroku login
After logging in successfully, you’ll have to create an application using the CLI;
cd into the root folder of the application and run the following command:
1$ heroku create stream-chat-app
Next, we’ll set up a server running on Express to serve the application. Create a file called "
server.js" in the root folder of the application, then open the file and update the file contents with the following:
The code above creates a Node server that serves the build files. The
/* route directs all requests to the
Also, install the packages used in the server by running the following command:
1npm install express express-favicon
Next, we'll update our
package.json scripts so that the
start command will start the express server instead of the dev server. Update the
scripts section of the
package.json file to look like the snippet below:
Before we deploy the application, we’ll have to deploy the API that we're making our requests to. Luckily, the server has one-click deployment to Heroku available! Head over to the GitHub repository of the Stream Chat API and follow the deployment instructions to deploy the API.
After deploying the API, we'll need to grab the URL provided and update the application to make requests to the new endpoint. Head over to the
./src/pages/auth/index.js file and update the URL:
YOUR_NEW_API_ENDPOINTwith the endpoint you get after deploying the API. Preferably, it’ll be best to store this value as an environment variable (in your
Commit all your changes and run the command below to deploy the application:
1$ git push heroku master
When the command runs to completion, it means your application has been deployed successfully! Run
heroku open to open the newly deployed application on your browser.
In this article, we looked at how we could create a messaging application using Stream and Stream React components. We also went through the authentication of users using the Stream Client and the API.
You can improve the application by persisting in the auth state, which means saving the information of the authenticated user locally using the local storage.
The source code of this application can be found on GitHub.