Real time private chatting app using React, Nodejs, mongodb and Socket.io — Part 4
Adding real-time chat feature and implementing Logout feature
Originally published at https://www.codershood.info on October 31, 2019.
This is a final and last part of the Building Real-time private chatting app using React. In this part, we will finish our application by adding the features listed below,
- If any user is selected from the chat list than we will fetch the conversation between users.
- We will add the real-time chat feature in this application.
- We will add the Logout feature.
A little recap again, To integrate the real-time morality in our application, we connected our React application to Socket Server. Later we implemented the Realtime chat list for the application. On the server-side, we wrote the Socket Server Event to Emit the updated Chat List. And at the end, we Highlighted the selected user from the list of users.
The last thing we did in the third part was highlighting a selected user from the chat list to start a new chat. We will start our implementation from where we left in the last part. So let’s start the implementation,
Fetching the conversation between users
As the title reads Fetching the conversation between users, it seems very easy, right! All you have to do is make an HTTP call and you are done. Well, this is exactly what you are going to do but there is a little problem.
ChatList
Component is a separate component and the Conversation
Component will be a separate Component, which we will create in next few minutes. So here you have to pass data between two sibling component.
So first we will create Conversation
Component and then we will display messages and do other things. As always I will divide this section's explanation into smaller chunks and this way we will speed the development of this application.
Creating Conversation Component
Let’s create Conversation
Component nothing so special about it. Create conversation.js
file inside /home
folder. Right now just write the below code in conversation.js
file,
conversation.js:
Now your Conversation
component is ready to use, So why wait let's import it into Home
component and see if it works!
Now you can add the <Conversation>
into your Home.js file, and it should show the Conversation Component works!
message. So at this point, your Home.js file should look like this.
Home.js:
Send data of the selected user from the chat list to the conversation Component
It’s a general thinking that; when you click on any user from the chat list you would like to see the conversation between you and that user. In this section, I will explain how to pass the data from the Chatlist
component to the Conversation
component.
=>Since you have already written complete chat list code in the last part, hence here you don't have to write anything.
=>Open the ChatList.js and you will find selectedUser()
method.
ChatList.js:
Explanation:
- The above code is very easy to understand, in the first line we have assigned the user id of the selected user from the chat list to the
selectedUserId
property. - The second line is kinda interesting for us since it would send the data to the other component.
- Here we will use Props and States to send data from ChatList component and receive data in Conversation component respectively.
In the below section we will catch the data sent from the Chatlist
component.
Receiving incoming data in Conversation component from ChatList component
Here we are not going to use Redux or any state management libraries since the scope of the app is not that big. Here we will use plain Props and States to transfer data between components.
To receive data from the ChatList component, First, we will have to get the data in Home Component.
Here we will create a state in a Home Component that will hold the currently selected user. This state will be updated by the function, which will be passed as props in the ChatList component.
=>Create a new method called updateSelectedUser()
in Home Component and add the below code in it.
=> Create a new property called selectedUser
in the state object to hold the value of the selected user. Now the State object your Home Class should look like this,
At this point, the Property of the state in Home Component is set to receive the updated user. Now let’s send the updated user details to Conversation Component using React props.
=> Update the getChatBoxComponent()
method as shown below,
Fetching the conversation between users from the server
In this section, we will make an HTTP call to fetch the conversation between the user from the server. So to do this, we will use the getMessages()
method. This method is defined inside the ChatHttpServer
class.
So open the C onversation.js and write down the below code. But first, add below two more properties inside the state object of the Conversation
Component class.
Conversation.js:
Whenever the Conversation will receive the new user’s data it will call the HTTP service to fetch the conversation between two users. To achieve this we will use two Component Lifecycle methods getDerivedStateFromProps()
and ComponentDidUpdate()
respectively.
Now to check the updated user’s data we will we are using getDerivedStateFromProps()
, which update our state with updated data hence the component will rerender itself. Open the C onversation.js and write down the below code.
Conversation.js:
Once the component will call the render() method, right after the ComponentDidUpdate()
method will execute. In this method, we will make an HTTP call to fetch the conversation between two users. Open the C onversation.js and write down the below code.
Conversation.js:
Explanation:
- The method
ComponentDidUpdate()
will give the previous Props and you will receive the new props in props property of the call. - By using these Two props, we can determine if the logged-in user has selected some other user in the chat list.
- After getting updated user’s data, we will call
getMessages()
method of the class.
Finally, In getMessages()
method of the class, we will consume the ChatHttpServer
class. Once we will receive the new messages, getMessages()
method will update the state and which will render the conversations between two users. Open the C onversation.js and write down the below code.
Conversation.js:
Explanation:
- Here we are calling
getMessages()
, which is defined inside theChatHttpServer
class. - The method
getMessages()
requiresuserId
(logged in user) and thetoUserId
(user selected from the chat list) which nothing but your selected user from the chat list. - Once we receive the response from the server, we will update the state using
conversations
property. - The
scrollMessageContainer
method, as the name suggests it will scroll the content to the bottom.
Let’s write a Nodejs express Route to return the response when we try to fetch the response from/getMessages
route. Open the routes.js and add the below route to it,
routes.js:
As you can see, we have called getMessagesRouteHandler()
method to handle the request and response for this route. So as always, it will send an appropriate response based on the result from the database.
Open the route-handler.js and the below method into it,
route-handler.js:
Explanation:
- First, we validated the request parameters and based on that server returns the response.
- Then inside the else block, we fetch the messages from MongoDB by calling
getMessages()
method. - If all goes as expected then we return a response to messages.
Now let’s fetch data from database using MongoDB query. Here I expect from you that you are familiar with MongoDB queries.
Open the query-handler.js file and add the below method, this method will basically fetch the messages from the MongoDB.
query-handler.js:
Explanation:
- The first and most important thing here is the MongoDB query. It’s a combination of or and operators, which will basically give the required result.
- And then we return a Promise, which resolves a query result.
And that’s it.
Rendering the conversation as a chat messages
At this point, you have all the messages between two users in conversation
property. The only thing is remaining now, is writing markup so that you can render messages.
=> Now open the conversation.jsand the below markup into the render()
method.
conversation.js:
Explanation:
- First, there will be an overlay on the Conversation Component, until you select any user from the chat list.
- Once you will select a user from the chat list, then we will show a message saying that; You are chatting with someone, for example, Chatting with Shashank
- Then based on the conversation state object we will fetch relevant UI (We will see this right after this section).
=> If you have noticed we have used two new methods i.e. this.getMessageUI()
and this.getInitiateConversationUI()
.
=> The this.getMessageUI()
will return the conversations in the form messages between two users and this.getInitiateConversationUI()
will return the placeholder if no user is selected from the chat list.
=> Now open the conversation.js and add these methods,
conversation.js:
Explanation:
- In
getInitiateConversationUI()
method will return JSX, which will be a placeholder. If the length of the conversation array will be 0 then this method will be called. - In
getMessageUI()
method, we are using.map
will return a list of messages in the form of HTML elements. alignMessage()
method will align the messages to left or right based on the user id of the user.
Now if you look at your screen you should see something similar to the below image,
Sending and Receiving Real-time messages
Finally! The last and the final puzzle of the application, here first we will send a message to the selected user from the chat list. And then, we will write a code to listen for the incoming messages from the server.
Since this section is a little long, hence we will divide this section into two parts. In the first part, we will write code to send the messages. In the second part, we will write code to receive the messages.
Sending real-time messages
So let’s start with the markup open the conversation.js and write the below code beneath the div
tag having.message-typer
class.
Here we don’t have too much to understand except keyup Event. In the keyup event, we will send the message to the server when the key code will be13
.’
In less technical terms when the user will press enter button we will send the message to the server.
conversation.js:
=>We have defined the sendMessage()
which will send the message to the server. So in the conversation.js file, add the below method,
conversation.js:
Explanation:
- First, we will check for the validation. If anything goes wrong with that, then we will show the alert.
- After that we inside
else
block, We have called another methodsendAndUpdateMessages()
. - Also, we will push this data into existing
conversation
state array. - Next, we actually send this data to Nodejs server by calling
sendMessage()
method, Which basically emits the socket event. - And at the end, we scroll the scrollbar to the bottom.
Now let’s addsendAndUpdateMessages()
method, inside the sameConversation
class.
Explanation:
- We will send this data to Nodejs server by calling
sendMessage()
method, which emits the socket event. - Also, we will push this data into existing
conversation
state array. - And at the end, we scroll the scrollbar to the bottom.
Now let’s add sendAndUpdateMessages()
method, inside the same Conversation
class.
All this work that we just did; is incomplete without writing the nodejs socket event. And also we need to save these messages in MongoDB.
The below socket event will listen to the socket event and based on the user’s id it will send messages to the recipients. Since it’s a socket event that we are emitting from Angular, So open the socket.js and add the below code,
socket.js:
Explanation:
- The first thing would be validation, check if everything is okay. If all goes well then we will go ahead and do the further operation.
- Inside the else block, we are calling two methods
getUserInfo()
andinsertMessages()
; both these methods are defined inside theQueryHandler
class. getUserInfo()
method will fetch socket id of the user who is intended to receive a message and theinsertMessages()
method as the name suggests will store the messages into a database.- And at the end, we will emit an event with the data and this data is nothing but the data received in the
add-message
event.
Receiving Real-time messages
This part is damn so easy to implement. Here we will create a method to listen for the incoming socket events. After receiving the socket event, we will push the new messages in the conversation
state array.
=> So I have created receiveMessage()
method inside the ChatSocketServer
class. This method will subscribe to the new incoming message from the socket server.
=> We will call this method from the componentDidMount()
method.
=> Once you call this method, it will listen to the incoming messages and automatically push the new messages in the conversation
state array.
So open the conversation.js and add the below inside thecomponentDidMount()
method.
conversation.js:
Now let’s createreceiveSocketMessages()
method and add the below code to it,
conversation.js:
Small tip, in case, if you want to show notifications. For example, you received a new message from Shashank.
You can do that here.
Explanation:
- This method will first check if the messages are from coming from the appropriate user by checking the user Id.
- Once you receive a new message, you will add that message into the
conversation
state property of theConversation
class. - And then again, we will move the scroll bar to bottom as a tradition.
Implementing Logout
Implementing Logout, yeah that the last thing is left to do. So here we will basically work only in HomeComponent
Class. I really don’t need to give an overview of Logout functionality.
So let’s just hop into home.js add the below markup in the render()
method, and make sure your header looks like below markup,
home.js:
Now open the home.js and the below code. In this below, we will consume the ChatSocketServer
to achieve this functionality.
=> Let’s add a method logout()
in Home component, which makes currently logged in user log out.
home.js:
Explanation:
- Inside the
logout()
method, we calledremoveLS()
method, which is defined inside theChatService
class. This method will delete the all the data stored in local storage related to this application. - Then After that, we have called the Logout method from
ChatSocketServer
class. This method will send a socket event to the server. This will change the online status to offline. - And once we receive the logout event response we will simply redirect the user to the home page.
Now the last part of the puzzle is a socket event that will change the status from online to offline. So open the socket.js and add the below event to it.
socket.js:
Explanation:
- The code
await queryHandler.logout(userId)
will modify the online status of the user by making a query into MongoDB database. - After doing that this event will emit the information of the logged out user in order to update the chat list.
- And on the front end, Angular will change the online status of the user.
Now the last part of the puzzle is a socket event that will change the status from online to offline. So open the socket.js and add the below event to it.
Final thoughts
If you are still with me from the start and you followed each and every step, then pat yourself on your back.
This series was too big, but I thought it was worth writing it. But the good thing is now you know, how to create a private chatting application in React with minimum complexity, for now, that’s the end of this series.
The complete source code is available on Github.
If you have any suggestions, questions, or feature requests, let me know in the below comment box, I would be happy to help. If you like this article, do spread a word about it and share it with others. Feel free to share your opinions in the below comments box. If you like this article do share it and leave a clap.