Socket.io Chat App with Vite+React
Getting Started with Chat Application
First lets create the Folder Structure for our Application
mkdir chat-app
cd chat-app
Now Create the Backend Folder Structure
mkdir chat-backend
cd chat-backend
npm init -y
Now install all the below required dependencies for our application.
npm install express socket.io
Create index.js in the root of the chat-backend project folder.
index.js
In Package.json file add a start script.
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
}
Now we will get started with the Express and Socket.io
Firstly we will import the required modules for our backend application.
const express = require('express')
const http = require('http')
const {Server} = require('socket.io')
Now lets create server with express and socket
This code sets up Socket.io to handle real-time communication and installs an Express server that listens on port 4000. A message (sendMessage event) sent by a user is broadcast to all clients that are connected.
const app = express()
const server = http.createServer(app)
const io = new Server(server, {
cors:{
origin: "http://localhost:5173",
methods: ['GET','POST']
}
})
io.on('connection', (socket) => {
console.log("A user connected: ", socket.id);
socket.on('sendMessage', (message) => {
io.emit('receiveMessage', message)
})
socket.on('disconnect', () => {
console.log("A user disconnected");
})
})
server.listen(4000, () => {
console.log("Server Listening on port 4000");
})
Now lets get started with our Frontend part using Vite. (Create a Vite Project in the root folder of Chat App).
npm create vite@latest
Next, we need to install a few dependencies. Navigate to the frontend app folder.
cd chat-frontent
npm install socket.io-client @chakra-ui/react @emotion/react @emotion/styled framer-motion
The following represents the structure of the frontend application:
chat-frontend/
│
├── src/
│ ├── components/
│ │ └── ChatBox.jsx
│ ├── App.jsx
│ └── main.jsx
├── index.html
└── package.json
Now let’s code the App.jsx file
import { ChakraProvider, Box, Heading } from "@chakra-ui/react";
import ChatBox from "./components/ChatBox";
function App() {
return (
<ChakraProvider>
<Box p={5}>
<Heading as="h1" mb={6}>
Socket Chat
</Heading>
<ChatBox />
</Box>
</ChakraProvider>
);
}
export default App;
ChatBox.jsx
import React, { useState, useEffect } from "react";
import { Box, Input, Button, HStack, VStack, Text, Avatar } from "@chakra-ui/react";
import { io } from "socket.io-client";
const socket = io("http://localhost:4000");
const ChatBox = () => {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState("");
const [userId, setUserId] = useState(null);
useEffect(() => {
// Generate or get userId from session storage
let storedUserId = sessionStorage.getItem("userId");
if (!storedUserId) {
storedUserId = Math.random().toString(36).substring(7);
sessionStorage.setItem("userId", storedUserId);
}
setUserId(storedUserId);
// Listen for messages
socket.on("receiveMessage", (message) => {
setMessages((prevMessages) => [...prevMessages, message]);
});
return () => {
socket.off("receiveMessage");
};
}, []);
const sendMessage = () => {
if (input.trim()) {
const message = {
userId,
text: input,
};
socket.emit("sendMessage", message);
setInput("");
}
};
console.log(messages,"MESSAGES");
return (
<VStack spacing={4} align="stretch">
<Box h="400px" p={4} borderWidth={1} borderRadius="lg" overflowY="auto">
{messages.map((msg, index) => (
<HStack key={index} justify={msg.userId === userId ? "flex-start" : "flex-end"}>
{msg.userId === userId && <Avatar name="Me" />}
<Box
bg={msg.userId === userId ? "blue.100" : "green.100"}
p={3}
borderRadius="lg"
maxW="70%"
>
<Text>{msg.text}</Text>
</Box>
{msg.userId !== userId && <Avatar name="Other" />}
</HStack>
))}
</Box>
<HStack>
<Input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Type a message"
/>
<Button onClick={sendMessage} colorScheme="teal">
Send
</Button>
</HStack>
</VStack>
);
};
export default ChatBox;
The Final Result