Creating Your Own Chat Room with React, Node, Socket.io and the Cloud: Part 2
Tags: react, node, cloud, beginners
Published: 2021-05-07 20:13:04

In this blog, we will complete everything we need to get our Chat Room up in running.

![Sample Chat Gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/235ocmmv7et47fli6i47.gif)

[In part 1](https://dev.to/ibmdeveloper/creating-your-own-chat-room-with-react-node-and-socket-io-in-the-cloud-part-1-13dg ), we focused on creating the socket.io NodeJs Server that would manage our chat. Its primary purpose was to receive messages from users in our Chat room and to send it to other Chat Room users in  in real time.

In part 2, we will be focusing primarily on the ReactJS front-end portion of the Chat room where users will view messages and send messages to other users and connecting it to our server.

NOTE: If you would like to follow along and build the application with me, I recommend you go back to part 1 and complete that portion before moving any further. The ReactJS portion of our application will not be able to work without a server to interact with.

{% link https://dev.to/ibmdeveloper/creating-your-own-chat-room-with-react-node-and-socket-io-in-the-cloud-part-1-13dg %}

To make our lives easier, I have created the base ReactJS application that we will be using to house our Chat Room. this includes the UI and visuals as well as some starter code that will allow us to code in what we need to connect to our Node server. To get the starter code, download the source from [my github](https://github.com/bradstondevcode/simple-react-chat-app-starter-code ).

So here is a brief overview of what we will cover is this particular blog to get the React portion of the application up and running:

So here is quick overview of what we will be doing with our Node server:

1. Install and configure our React application to use socket.io

2. Implement Socket methods to allow our React application to communicate with our server( NodeJS application)

3. Locally Test our React applications connection to our Node Server

4. Deploy our ReactJS application to the cloud so it can be accessible to users from anywhere.

As you may have noticed, a lot of what we will be doing in this blog will parallel what we did in the last blog. This portion of development should be a bit faster as we should now have a base understanding of how socket.io works from the previous blog.

So without further adieu, let's get started...

# Installing and Configuring Socket.io with ReactJS

So the first thing we are going to do, is navigate to our base ReactJS code using the terminal or command line. Our code should look something like this:

```bash
cd <you-path-directory>/simple-react-chat-app
```

Once we have navigated to our source code, we are going to install all of our base dependencies listed in our package.json file using this command:

```bash
npm install
```

Once we have installed all of the base frameworks and dependencies we need to run our application, it's time for us to install socket.io into our application. We will be installing the socket framework almost exactly how we did it on the NodeJS server except that we will be using a different library to get access to socket.io in our client application. Here is what we will run to install socket.io in React:

```bash
npm install socket.io-client --save
```

As you have probably noticed, this is the "client" version of the socket.io. If you are interested in learning more about the client version of socket.io check out this link: [socket.io Client documentation](https://socket.io/docs/v4/client-installation/)

Our next step will be to create a file that will be used to manage our client socket.io connection with our server. For ease, I have already created the file for you but it is currently blank. We will be adding the necessary code in the next few steps.

First, open the folder titled "src" in our React app source code directory and the open the folder titled "services". In the "services" folder, you will find a file titled "socket.js". We will be inserting all necessary socket.io connection code in this file. Open this file and add this code:

```bash
import socketIOClient from "socket.io-client";

const serverEndpoint = "<your-nodejs-server-url>";

export const socket = socketIOClient(serverEndpoint, {
	transports: ['websocket']
});
```
In the first line we are importing are _socket.io-client_ library into our file for use.

In the next line of code, we are setting the _serverEndpoint_ to our NodeJs server. This is the string value of the url that your Node server is currently hosted. For example, my _serverEndpoint_ line would look like this:

```bash
const serverEndpoint = "simple-node-chat-server-bsh.us-south.cf.appdomain.cloud";
```
Our next line is actually initializing the connection between our client and our server. We are also specifying in this line of code a transport parameter. Essentially, what that is doing is setting the connection protocol we would like to use in our socket connection to our server. If you would like to learn more about how transports work and the the different typed of connection protocols, check out this [link](https://socket.io/docs/v4/client-initialization/#transports).

We now have all the code we need to connect to our socket.io NodeJs server. The reason we are creating a separate file to manage this connection, is because now if we desire to expand this application in the future, we have one location that handles this connection. We can then easily import this file into any React Component or file that we would like to use our socket.io connection with.

With that, we have set up our React application to connect to our NodeJS server. Our next step will be to implement the socket.io methods we need to communicate appropriately with our server.

# Implementing Socket Methods in ReactJS client

Since we already have everything we need setup on our server, our next job is to implement the correct methods to communicate with our server.

In order to do that, we will need to modify the code in our ChatRoom.js file. In our source code directory, open the 'src' folder and then open the "pages" folder. In the "pages" folder, open up the file titled "chatRoom.js". As the title of the file suggests, this holds all relevant code we need to operate our chat room.

As you will notice in the file, there is quite a bit of code already implemented, but we need to implement some new code to get our socket methods working.

At the top of the file directly under our last imported file we are going to import our "socket.js" file from our services folder. Your code should look something like this:

```bash
...
import ChatNotification from '../components/ChatNotification'

//Add socket import here
import {socket} from '../services/socket' 

let styles = {
....
```

Now that we have our socket service imported, our first step is to setup the socket.io method that manages creating and setting our user data/identity. In order to do this we need to implement a _socket.on_ method and _socket.emit_ method. 

As mentioned in [part 1](https://dev.to/ibmdeveloper/creating-your-own-chat-room-with-react-node-and-socket-io-in-the-cloud-part-1-13dg) of this blog, _socket.on_ methods act as listeners, always looking out for messages and _socket.emit_ methods act as messengers, sending messages to listening _socket.on_ methods. In this case, _socket.on_ methods are listening for messages **from** the Node server and _socket.emit_ methods are sending messages **to** the Node server.

In our ChatRoom.js file, in our componentDidMount() method, we will be implementing our code. Within the _if(!userIDVal){_ we will be adding new code that looks like this:

```bash
if(!userIDVal){

   socket.on("SetUserData", userData => {
      //When user creation on server is complete, retrieve and save data to local storage
      localStorage.setItem('userID', userData.userID)
      localStorage.setItem('username', userData.username)
	        console.log(userData)

      this.setState({currentUsername: userData.username, currentUserID: userData.userID})

      //Notify Socket server is not ready to chat
      socket.emit("UserEnteredRoom", userData)
   });

   //Send Socket command to create user info for current user
   socket.emit("CreateUserData")
} 
```

So what exactly is happening here?

So what we are doing is checking to see if our current client/user has a Chat Room "identity" yet. In code prior to this conditional you will see this:

```bash
let userIDVal = localStorage.getItem('userID')
		let usernameVal = localStorage.getItem('username')
```

What this code is doing, is attempting to retrieve _userID_ and _username_ data stored in our browsers local storage. If the data does not exist (_if(!userIDVal)_), we are assuming that this is the users first time in the chat room. 

The first thing we do is implement a _socket.on_ method with name "SetUserData" that will begin listening for the server to send information about this users newly made identity. Within that _socket.on_ method_ we have some code that retrieves newly created user data from the server and then promptly saves it to the browser's local storage for future use and sets the values in the React components state. Once the user info is set, we use the _socket.emit_ method "UserEnteredRoom" to let the server know that the user is now entering the Chat room with an identity and can chat.

After we setup the _socket.on_ method, "SetUserData", we then implement a _socket.emit_ method called "CreateUserData" which will be used to actually ask the server to make an identity for our user. The emit will send the message to create user data for our client and the server will promptly send a message back to be retrieved by our listening "SetUserData" method.

NOTE: The reason we don't write these two methods in reverse order is to ensure that the listener, "SetUserData", is prepared to receive newly created user data from the server **before** we ask the server to make new user data. In some cases, the request for new user data and its response may be fast, and if we set the listener method after the messaging function, there is a chance the listener method may still be getting setup and miss the server's response. If that doesn't make sense, please feel free to leave a comment asking for more clarification.

Now that we have added code for a first time chat user, it is also necessary for us to have things set up for a returning user with pre-existing user data stored in the browser.

In the else condition of our _if(!userIDVal)_ conditional, we will add this code:

```bash
else {
   //If user already has userid and username, notify server to allow them to join chat
   this.setState({currentUsername: usernameVal, currentUserID: userIDVal})
   socket.emit("UserEnteredRoom", {userID: userIDVal, username: usernameVal})
}
```

If the user exists in browser local storage, we simply store that information to React state and send a message to the server using the "UserEnteredRoom" socket.io method to inform our server that our client is ready to chat.

The next piece of code we will be entering will be at the end of our _componentDidMountMethod()_. This code will simply setup up a _socket.on_ method called "RetrieveChatRoomData" that will always be listening for new Chat Room data, aka when a new chat message has been received by the server. This the code that we will add:

```bash
socket.on("RetrieveChatRoomData", (chatRoomData) => {
   this.setState({chatRoomData: chatRoomData}, () => this.shouldScrollToBottom())
})

```

With that new addition our complete componentDidMount() method should look like this:

```bash
componentDidMount(){

	// localStorage.removeItem('userID')
	// localStorage.removeItem('username')

	let userIDVal = localStorage.getItem('userID')
	let usernameVal = localStorage.getItem('username')

	//If user does not have a userid and username saved in local storage, create them for them
	if(!userIDVal){

	  socket.on("SetUserData", userData => {
	    //When user creation on server is complete, retrieve and save data to local storage
	    localStorage.setItem('userID', userData.userID)
	    localStorage.setItem('username', userData.username)
	    console.log(userData)

	    this.setState({currentUsername: userData.username, currentUserID: userData.userID})

	    //Notify Socket server is not ready to chat
	    socket.emit("UserEnteredRoom", userData)
	  });

	  //Send Socket command to create user info for current user
	  socket.emit("CreateUserData")
	} 
	else {
		//If user already has userid and username, notify server to allow them to join chat
		this.setState({currentUsername: usernameVal, currentUserID: userIDVal})
		socket.emit("UserEnteredRoom", {userID: userIDVal, username: usernameVal})
	}

	//Retrieve game data (from Get Chat data socket call)
	socket.on("RetrieveChatRoomData", (chatRoomData) => {
		this.setState({chatRoomData: chatRoomData}, () => this.shouldScrollToBottom())
	})

}
```

Next we will implement the method that will actually send the chat messages to our server.

Find the method called _sendMessageData()_ in our file. In this empty method we will be adding this code:

```bash
var {message, currentUsername, currentUserID} = this.state

if(message.length > 0){
	//Send chat message to server...
	socket.emit("SendMessage", {message: message, username: currentUsername, userID: currentUserID, timeStamp: null})
	//Clear chat message textfield box
	this.setState({message: ''})
}
```

This code first retrieves our current entered message, our username and our userID from our React state and stores them as variables for future use. Next, we check to make sure the message has some length, otherwise we risk sending an empty message to the server. If the message length is greater than zero, we then use the _socket.emit_ method "SendMessage" to send our typed in chat message with the information on who sent the message. NOTE: I added an extra timestamp data point just in case I wanted to add timestamps in the future to the chat view.

Once we have sent the message to the server we empty our message string from our React state which in turns clears our textfield input box. 

With that last addition our Chat Room is almost ready. There is one minor housekeeping-code addition we need to add in order to prevent against possible memory leaks.

As I mentioned earlier, whenever we implement a _socket.on_ method, we are telling our code to constantly listen to messages that may come from our server. The thing is, if you do not tell the listeners to stop listening, they will continue to listen pretty much indefinitely as long as the application is running. So if we by-chance, navigated to another page within our application, the listeners would keep on listening even though we are no longer on the page that needed the listeners. **That**, my friends, is essentially a memory leak. Because if we kept navigating to and from our page with the listeners it would keep adding listeners over and over and over, bogging down our application.

With all that being said, we need we need to add a set of clean-up methods that turn off those listeners when we leave the chat room page. 

Somewhere in the code, preferably directly under the _componentDidMount()_ method add this method and code:

```bash
componentWillUnmount(){
	socket.off("RetrieveChatRoomData")
	socket.off("SetUserData")
}
```

As the _socket.off_ method implies, it "turns off" the listening of these functions when we unmount this particular view or leave this page entirely. 

Before we declare victory on our Chat Room app, I would like us to add one more convenience method to our React application that will allow us to clear our chat history whenever we would like.

In the "pages" folder within our "src" directory of our project, open the file titled "ClearChat.js". 

At the top of the file, import socket below the last import:

```bash
...
import { Row, Container } from 'react-bootstrap';

import {socket} from '../services/socket'
```

Once we have added the import, scroll down until you find the empty method called _clearChatData()_. In that method we will add one simple line:

```bash
socket.emit("ClearChat")
```

As the _socket.emit_ suggests, this will send a message to our Node server to clear our chat history. This functionality can only be used by navigating to the "/clearChat" page when we run our application.

With that our Chat Room application is ready to go. Before we deploy our application to the cloud, we are going to briefly test if our application is configured correctly on our local machine. This way we won't be surprised by any errors when we attempt to push it to the cloud.

# Local Test of React/Node Server Connection

So let's do a quick test to see if our React application is properly configured and setup to connect with our socket.io NodeJS Server.

In a terminal/command line window, make sure you are currently in our _simple-react-chat-app_ directory. Once we are sure we are in our directory, let's run a command that will run our React application locally. Type this command into your terminal:

```bash
npm start
```

This should begin locally running our React code in our browser on our localhost (most likely port 3000). In most cases, the application should open automatically in your default browser, if not, enter http://localhost:3000 into your desired browser to view the application. If your application ran successfully, you should see something like this:

![React-App-Local-Host-Chat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vo99b6rc3q196xkx58by.png)
 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3pwabyxv7p1h5mr1zae.png)

It should simply note that someone entered the chat (which was you!). At the top of the screen below the "Chat Room" title it should show who you are now appearing as in the chat. Go ahead and navigate to the bottom of the page and type something into the chat message input box. Send your message by either pressing the send icon or pressing Enter/Return. You should now see your message appear in the chat.

![React-App-Hello-Chat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c1p9bphpm8qp9dbo4c0j.png) 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3pwabyxv7p1h5mr1zae.png)

If that worked, that means your Node server in the Cloud is working and your react application is communicating correctly with it. If that did not work, go back and ensure your code matches what was shared above. NOTE: Also, check your browser web console (normally accessible via developer tools) to check if you are receiving an errors. This may give you guidance on your issue. 

If you want to check what it would be like to have more than one individual in the Chat Room, Open a different browser (E.g. If you are currently testing with Firefox, now open the Chat Room with Chrome) to see how it works.

Now that we see the general chat Room functionality is working, let's just test that our Clear chat functionality is working. 

In your browser address bar go to this address: http://localhost:3000/clearChat (Note: If your React is hosting at a different port replace 3000 with that port).

You should be presented with a simple page that looks like this:

![React-App-Clear-Chat-View](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/81nyajkkqssaiqjmdgnk.png) 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3pwabyxv7p1h5mr1zae.png)

Click the button on the page that says "Clear Chat".

Once you have done that, navigate back to main page (http://localhost:3000) and you should now see that the chat cleared itself. NOTE: You will only be able to clear the chat while running the application on your local machine. When hosted in cloud, I did not make it possible to route directly to Clear Chat. Feel free to add that capability if you'd like.

Now that we have tested this locally, it's time to deploy this Chat Room into the cloud. Go ahead and stop the React application so we can move on to the next steps. 

# Deploying your React chat Room to the Cloud

The following steps are going to be almost identical to what we did to deploy our Node server to the cloud so quite a bit of this will be familiar. The biggest difference will be the name of our Application and the route and making sure we initiate a React build before we deploy.

The first thing we are going to need to do is build our React application so it can be properly deployed on our Cloud server (IBM Cloud Cloud Foundry server). So let's go ahead and run this command to build our React app:

```bash
npm run build
```

That should initiate the React build process. This may take a few minutes and your terminal window should look something like this:

![CLI-successful-react-app-build](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r1459jl9t14u89bnvtin.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3pwabyxv7p1h5mr1zae.png)

Now in order to have a free way to easily deploy our application to the cloud, we will be using an [IBM Cloud Lite account](https://www.ibm.com/cloud/free). 

If you do not have IBM Cloud Lite account, you can quickly sign-up for free access to cloud resources for hosting your application in the cloud. Signup using this link: [IBM Cloud Signup Link](https://cloud.ibm.com/registration).

Once you are signed up we will be pushing our application to the cloud using IBM Cloud CLI in our terminal. If you do not have the IBM Cloud CLI, you can download the latest version here: [IBM Cloud CLI](https://www.ibm.com/cloud/cli).

NOTE: If you are interested on how to do this through the IBM Cloud dashboard, you can check out my blog on deploying a React application to the cloud for general walkthrough of how that works: [Deploying ReactJS to the Cloud](https://dev.to/ibmdeveloper/deploying-your-first-reactjs-application-into-the-cloud-31je).

Now, make sure you are still in a terminal window and that you are still in the _simple-react-chat-app directory.

While in the directory, log into your IBM Cloud account using this command:

```bash
ibmcloud login
```

Enter you username and password and you should be presented with a screen like this:

![CLI-IBM-Cloud-Login](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a0wieoic3xhh8dv4sphx.png) 

![CLI-Authenticated-Success](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nzhmrydq2em8u5aq3uan.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3pwabyxv7p1h5mr1zae.png)

Once you have logged into IBM Cloud, we need to set our IBM cloud target to Cloud Foundry as we will be using the Cloud Foundry framework to host our application. If you'd like to learn more about Cloud Foundry, check out this link: [Cloud Foundry](https://www.ibm.com/cloud/cloud-foundry). Type this command to target Cloud Foundry:

```bash
ibmcloud target --cf
```

If it was successful, you should see something like this:

![CLI-Target-CF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d3izbju5g1z55wnr5hqv.png) 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3pwabyxv7p1h5mr1zae.png)

Right before we deploy our server to the cloud, we need to make some minor updates to our code.

In our _simple-react-chat-app_ directory and open the file named "manifest.yml"

In the file you should see this:

```bash
applications:
  - name: Simple React Chat App
memory: 64M
path: build/
buildpack: staticfile_buildpack 
routes:
  - route: simple-react-chat-app-<your-intials>.<server-closest-to-you>.cf.appdomain.cloud
```

Replace _<your-initials> with your initials and _<server-closest-to-you>_ with a the server closest to you. Because you may not know what are possible server names, here is a list. Choose a server that you believe you think may be closest to you. And if you want to view this list yourself you can enter the command listed below:

```bash
ibmcloud regions

//Output
Name       Display name   
au-syd     Sydney   
in-che     Chennai   
jp-osa     Osaka   
jp-tok     Tokyo   
kr-seo     Seoul   
eu-de      Frankfurt   
eu-gb      London   
ca-tor     Toronto   
us-south   Dallas   
us-east    Washington DC   
br-sao     Sao Paulo  
```

For example, this was my updated manifest.yml(NOTE: Please do not use the same route name as displayed below. This will likely cause an error saying route is already taken when you attempt to push to IBM Cloud):

```bash
applications:
  - name: Simple React Chat App
memory: 64M
path: build/
buildpack: staticfile_buildpack 
routes:
  - route: simple-react-chat-app-bsh.us-south.cf.appdomain.cloud
```

Once you have updated your manifest.yml, you only have one more step: **Deploy your React application into the Cloud!**

In the same terminal window you logged into IBM Cloud with, enter this command:

```bash
ibmcloud cf push
```

This will initiate the process of deploying your NodeJS application into the cloud. It in general takes a few minutes to deploy this code.

When the the application has been successfully deployed, you should see something like this in your terminal window:

![CLI-React-app-successful-push](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6l7qntk5o1ojffqrpaq.png)
 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3pwabyxv7p1h5mr1zae.png)

Go to a browser window and insert the route value you entered into the manifest.yml. In my case that would be

```bash
simple-react-chat-app-bsh.us-south.cf.appdomain.cloud
```

You should be presented with our Chat Room and with the message that a new user entered the chat. If you did not clear the chat in our previous step, you will likely see the messages you sent earlier while testing:

![React-App-Deployed-Chat](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/195a5sppuhuzlyv5tcvj.png) 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q3pwabyxv7p1h5mr1zae.png)

If you do not see this page, you may need to check that you code matches the code I shared above and feel free to check the actual application status and error log by visiting the IBM Cloud Resource list and finding your application by its name.

And just like that, we have a working chat room that can be shared with whomever you like!!

I really encourage you to take the time to really understand what all this code I have shared with you is doing. Change method names, change how data is sent, and just break things! This is the best way to truly understand what is happening under the hood so that you can use socket.io to implement realtime communication in applications like this.

Since socket.io's real-time messaging can be used in a lot of different scenarios, I'd like to hear from all of you.

**What other ways could you imagine using the socket.io technology other than a chat room?** Leave you ideas in the the comments below. I'd love to hear them!

Thanks for reading this blog and I am encouraged by your desire to learn new topics like these.

Have a great one until next time!

==== FOLLOW ME ON SOCIAL MEDIA ====
Twitter: [Bradston Dev](https://twitter.com/BradstonDev)
Dev.to: @BradstonDev 
Youtube: [Bradston YT](https://www.youtube.com/channel/UC6Ky8s71RP65akLb_XV1_OA)