Real-Time Chat App with MERN and Socket.IO

MERN | Nexsaar

1. Introduction

Real-time chat applications have become essential in modern web development, whether for messaging platforms, customer support systems, or collaborative tools. The MERN stack (MongoDB, Express.js, React, Node.js) combined with Socket.IO enables developers to build scalable, real-time communication apps with ease. This blog will provide a step-by-step guide to building a real-time chat app, complete with backend and frontend integration.

Nexsaar Technologies - React JS, Node JS, Odoo, Salesforce, Java Development Services

Key Concepts of Real-Time Communication

  • WebSockets: A communication protocol that provides full-duplex channels over a single TCP connection.

  • Socket.IO: A JavaScript library that abstracts WebSocket handling, adding fallbacks, rooms, namespaces, and reliability.

  • MERN Stack: Combines MongoDB, Express, React, and Node.js to provide a full-stack environment.

Project Setup

Initialize the project and install dependencies:

mkdir chat-app && cd chat-app
npm init -y
npm install express socket.io mongoose cors dotenv
npx create-react-app client
cd client && npm install redux react-redux @reduxjs/toolkit socket.io-client axios

Backend with Node.js, Express, MongoDB, and Socket.IO

Let’s configure the backend server that connects to MongoDB and enables Socket.IO for real-time communication.

const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv').config();

const app = express();
const server = http.createServer(app);
const io = socketIo(server, { cors: { origin: '*' } });

app.use(cors());
app.use(express.json());

// MongoDB Connection
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB connected'))
.catch((err) => console.log(err));

// Message Schema
const messageSchema = new mongoose.Schema({
user: String,
content: String,
timestamp: { type: Date, default: Date.now }
});
const Message = mongoose.model('Message', messageSchema);

// Socket.IO Events
io.on('connection', (socket) => {
console.log('User connected:', socket.id);

socket.on('sendMessage', async (data) => {
const newMessage = new Message(data);
await newMessage.save();
io.emit('receiveMessage', newMessage);
});

socket.on('disconnect', () => {
console.log('User disconnected');
});
});

server.listen(5000, () => console.log('Server running on port 5000'));

Frontend with React, Redux, and Socket.IO Client

The frontend connects to the backend and renders chat messages in real-time. Redux is used for state management.

import React, { useState, useEffect } from 'react';
import io from 'socket.io-client';
import { useDispatch, useSelector } from 'react-redux';
import { addMessage, setMessages } from './messageSlice';

const socket = io('http://localhost:5000');

function ChatApp() {
const [message, setMessage] = useState('');
const dispatch = useDispatch();
const messages = useSelector((state) => state.messages);

useEffect(() => {
socket.on('receiveMessage', (msg) => {
dispatch(addMessage(msg));
});
}, [dispatch]);

const sendMessage = () => {
const msgData = { user: 'User1', content: message };
socket.emit('sendMessage', msgData);
setMessage('');
};

return (

<div>
  <h2>Real-Time Chat</h2>
  <div
    style={{ border: '1px solid #ccc', height: '300px', overflowY: 'scroll' }}
  >
    {messages.map((msg, index) => (
      <p key={index}>
        <strong>{msg.user}:</strong> {msg.content}
      </p>
    ))}
  </div>
  <input value={message} onChange={(e) => setMessage(e.target.value)} />
  <button onClick={sendMessage}>Send</button>
</div>
); }

export default ChatApp;

Redux Slice for Messages

import { createSlice } from '@reduxjs/toolkit';

const messageSlice = createSlice({
name: 'messages',
initialState: [],
reducers: {
addMessage: (state, action) => {
state.push(action.payload);
},
setMessages: (state, action) => {
return action.payload;
}
}
});

export const { addMessage, setMessages } = messageSlice.actions;
export default messageSlice.reducer;

Enhancements to Add

  • User authentication (JWT-based)

  • Private messaging with Socket.IO rooms

  • Typing indicators

  • Online/offline user tracking

  • File/image sharing

  • Deployment with services like Heroku, Vercel, or AWS

Conclusion

By combining MERN with Socket.IO, we can build scalable, feature-rich real-time chat apps. This setup can be extended with authentication, private chats, notifications, and more. The combination of WebSockets and MERN makes building modern, real-time applications easier than ever.

More articles

Modern Authentication Solutions for JavaScript Developers

Explore modern, secure, and developer-friendly authentication approaches tailored for JavaScript applications. Learn how to simplify login, authorization, and session management without unnecessary complexity.

Read more

Odoo 19 Feature: What’s New Features and Why It Matters

The world of business software is in constant motion, and Odoo, the leading open-source ERP platform, is once again at the forefront of this evolution. As the highly anticipated Odoo 19 release approaches, a wave of powerful updates is set to redefine how businesses operate.

Read more