Welcome folks today in this blog post we will be building a socket.io room based group chatting application inside react JS at the front end and we will be using node JS at the backend using JavaScript all the source code of this application will be given below.
Get Started
So first of all guys we need to initialise a simple empty directory in which we will be holding all the project files
mkdir realtimechat
cd realtimechat
Making the Frontend
so first of all we will be creating the front end of the project this will be a simple react JS application so now just follow the step-by-step instructions which is given to create a simple react JS application
npx create-react-app chatapp
cd chatapp
npm i react-router-dom
npm i socket.io-client
As you see that we have installed all the dependencies which will be needed for this react JS project first of all we are installing the react-router-dom dependency which is able for routing purposes inside the application and then we are installing the socket.io client library specifically designed for react applications so after you install all these dependencies guys your package.json file will look something like this
Directory Structure of App
Now you can just see guys the directory structure of this application. so these are the files and folders we will be needing for this project screenshot is shown below
Initializing the Routes of App
Now in the first step guys we will be initializing all the routes that will be required for this application so specifically there will be two routes for this application so for modifying this you need to open your App.js file for of your of your access application and copy paste the below code
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import React from "react"; import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; import "./index.css"; import Home from "./Home/Home"; import ChatRoom from "./ChatRoom/ChatRoom"; function App() { return ( <Router> <Switch> <Route exact path="/" component={Home} /> <Route exact path="/:roomId" component={ChatRoom} /> </Switch> </Router> ); } export default App; |
As you can see that lies in the above code we are importing the required dependencies from react-router-dom first of all we import in the browser router and in each route we are providing the path property path is actually the actual URL of the route so we have the first for the home page and secondly for the actual room ID so this room it will be provided as a dynamic parameter to the URL and also there is a second component property guys so component property refers to the actual component which will be loaded whenever you open this route in browser And now we are importing both the components that will be needed for this application at the very top by the import statement in the next step we will be creating these two components
Making the Homepage Component
Now we will be making the homepage component inside every applications first for you need to make a home folder inside that we need to define two files these two files will be for CSS and the actual component which would be the jsx file so the screenshot is shown below
Home.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import React from "react"; import { Link } from "react-router-dom"; import "./Home.css"; const Home = () => { const [roomName, setRoomName] = React.useState(""); const handleRoomNameChange = (event) => { setRoomName(event.target.value); }; return ( <div className="home-container"> <input type="text" placeholder="Room" value={roomName} onChange={handleRoomNameChange} className="text-input-field" /> <Link to={`/${roomName}`} className="enter-room-button"> Join room </Link> </div> ); }; export default Home; |
As you can see guys we have a simple input field where we are taking the input of the room name of this chat application so the user has the option to select their favourite room name and they will enter inside this input field and then we have a simple button to submit the form and also to store this data guys we are initializing a use State Hook to store the room name and also we have the function to modify the state as well which is setRoomName() so whenever the data is changed inside the input field we are attaching a onchange event listener so inside this method the are simply setting the room name and also guys we after we press the button we are using the link method which will actually redirect the user to the actual route where inside this route we are providing the room name as an argument so whenever the user let’s on this button they will go to the respective room.
Home.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
.home-container { position: fixed; left: 10%; right: 10%; top: 50%; transform: translate(0, -50%); display: flex; flex-direction: column; } .text-input-field { padding: 24px 12px; border-radius: 7px; font-size: 24px; } .text-input-field:focus { outline: none; } .enter-room-button { margin-top: 20px; padding: 24px 12px; font-size: 28px; background: #31a24c; color: white; font-weight: 600; text-align: center; text-decoration: none; border-radius: 7px; } |
Making the Chat Room Component
Now we will be the defining the chatroom component where we will be chatting with other people so for defining this you need to make a separate folder called as chat true inside this we will be making the two files which will be for the CSS and the jsx files so the screenshot is shown below
ChatRoom.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
import React from "react"; import "./ChatRoom.css"; import useChat from "../useChat"; const ChatRoom = (props) => { const { roomId } = props.match.params; const { messages, sendMessage } = useChat(roomId); const [newMessage, setNewMessage] = React.useState(""); const handleNewMessageChange = (event) => { setNewMessage(event.target.value); }; const handleSendMessage = () => { sendMessage(newMessage); setNewMessage(""); }; return ( <div className="chat-room-container"> <h1 className="room-name">Room: {roomId}</h1> <div className="messages-container"> <ol className="messages-list"> {messages.map((message, i) => ( <li key={i} className={`message-item ${ message.ownedByCurrentUser ? "my-message" : "received-message" }`} > {message.body} </li> ))} </ol> </div> <textarea value={newMessage} onChange={handleNewMessageChange} placeholder="Write message..." className="new-message-input-field" /> <button onClick={handleSendMessage} className="send-message-button"> Send </button> </div> ); }; export default ChatRoom; |
As you can see that guys in the above code we are rendering all the messages in the particular room out there so also we have a simple input field to enter a new message in the room so we’re taking the room ID as an argument or a property inside this component and also we are defining a custom hook which is called as useChat and inside this custom hook component guys we are passing the room id and this custom hook will return the messages and the method which is used to modify those messages so in the next step will be defining this custom hook apart from that we have a simple input event handler for the field where we will be entering all the messages so give that input field changes then we are attaching the newly created message to the actual messages array and also we have a send message button when we click that button We are sending this message to the custom hook useChat by using the sendMessage() method
Creating the Custom Hook useChat
As you can see that guys in the src directory we are defining a simple file called as we useChat.js this will be the actual file will be storing all the messages which are passed in a particular room
useChat.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import { useEffect, useRef, useState } from "react"; import socketIOClient from "socket.io-client"; const NEW_CHAT_MESSAGE_EVENT = "newChatMessage"; const SOCKET_SERVER_URL = "http://localhost:4000"; const useChat = (roomId) => { const [messages, setMessages] = useState([]); const socketRef = useRef(); useEffect(() => { socketRef.current = socketIOClient(SOCKET_SERVER_URL, { query: { roomId }, }); socketRef.current.on(NEW_CHAT_MESSAGE_EVENT, (message) => { const incomingMessage = { ...message, ownedByCurrentUser: message.senderId === socketRef.current.id, }; setMessages((messages) => [...messages, incomingMessage]); }); return () => { socketRef.current.disconnect(); }; }, [roomId]); const sendMessage = (messageBody) => { socketRef.current.emit(NEW_CHAT_MESSAGE_EVENT, { body: messageBody, senderId: socketRef.current.id, }); }; return { messages, sendMessage }; }; export default useChat; |
As you can see that guys in this file by defining all the logic which will be required to build this chatting kind of an application for first of all we are defining the URL of the backend server where we will be hosting this socket.io server and at the very top you are importing the dependency for the client library of socket.io and Also we are defining the socke.io message event name.
As you can see inside this custom hook we are passing the room ID and then we are defining the use State hook for the messages Initial value will be empty array and also guys we are using the useref hook for the actual socket.io reference and then we have a simple useeffect hook guys inside that hook we are connecting to the the socket.io using the client library and we are passing the actual server URL the first argument and the second argument we are passing the actual room ID as a query parameter and then we are listening for different kinds of event for whenever the chat message event is been triggered or being received Then we are simply making a simple object called as incoming message and basically we are appending that message into the array preserving the old array values and also the second property guys we are basically checking that if the message is sent by the the current user or it has been received by him so for that we have a simple we are having a condition to check the sender ID and then at last we are setting the messages using the set messages method so whenever the user presses the send message button guys we also binded a simple method in this method we are defining we are sending a custom event to the server which is called as new chat message event and inside the argument we are passing the actual message that is sent in the body and the sender ID will be equal to the current ID of the socket that’s it and lastly we are returning the actual messages and send message method from this hook
ChatRoom.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
.chat-room-container { position: fixed; left: 0; right: 0; top: 0; bottom: 0; display: flex; flex-direction: column; margin: 16px; } .room-name { margin-top: 0; } .messages-container { flex: 1; min-height: 100px; overflow: auto; border: 1px solid black; border-radius: 7px 7px 0 0; } .messages-list { list-style-type: none; padding: 0; } .new-message-input-field { height: 200px; max-height: 50%; font-size: 20px; padding: 8px 12px; resize: none; } .message-item { width: 55%; margin: 8px; padding: 12px 8px; word-break: break-word; border-radius: 4px; color: white; } .my-message { background-color: rgb(0, 132, 255); margin-left: auto; } .received-message { background-color: #3f4042; margin-right: auto; } .send-message-button { font-size: 28px; font-weight: 600; color: white; background: #31a24c; padding: 24px 12px; border: none; } .messages-container, .new-message-input-field, .send-message-button { border-color: #9a9a9a; } |
Making the Backend Node.js & Express Server
Now we will be making the backend node JS server where we will be hosting the socket.io server you first fall for making that project you need to follow the step-by-step instructions which is given below
npm init -y
so this will create the package.json file for your node JS project now we need to install the dependencies which will be read it for this project
npm i socket.io
so as you can see that guys here in storing the socket.io library for our node.js project
now we need to define the index.js file which will be the starting point for our express server so thus copy paste the below code
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
const server = require("http").createServer(); const io = require("socket.io")(server, { cors: { origin: "*", }, }); const PORT = 4000; const NEW_CHAT_MESSAGE_EVENT = "newChatMessage"; io.on("connection", (socket) => { console.log(`Client ${socket.id} connected`); // Join a conversation const { roomId } = socket.handshake.query; socket.join(roomId); // Listen for new messages socket.on(NEW_CHAT_MESSAGE_EVENT, (data) => { io.in(roomId).emit(NEW_CHAT_MESSAGE_EVENT, data); }); // Leave the room if the user closes the socket socket.on("disconnect", () => { console.log(`Client ${socket.id} diconnected`); socket.leave(roomId); }); }); server.listen(PORT, () => { console.log(`Listening on port ${PORT}`); }); |
As you can see that guys in the above code we are defining our simple http server and we are passing the socket.io reference to it and we have started this server on port number 4000 and inside this socket.io server the is we are listening for the event whenever the user is connected at the client site we are listening for the actual event where the message will be received from the client side
Whenever user try to select or try to enter a custom room name and whenever they click join button this will Trigger on this will send a request at the server side and we can extract the room ID from the handshake parameter in the socket.io property so to join into the roomId using the socket.io join() method after joining in that specific room ID we can listen for specific events so here we are listening for all the incoming messages which will be coming from the client side and whenever a message comes we are simply using a simple broadcast event Which is only broadcasting those messages to only people which is present inside that specific room ID and also we have a disconnect event also guys whenever the user try to disconnect from the room ID we are removing that user from the room ID