Building a Real-Time Chat Application with Node.js and React

In today’s digital world, chat applications are essential for communication. Whether for customer support, community engagement, or simply keeping in touch, having a chat feature can significantly enhance user interaction. In this blog, we’ll build a real-time chat application using Node.js and React, two powerful technologies that allow for dynamic, scalable applications.

Prerequisites

Before we begin, ensure you have the following installed on your system:

  • Node.js: Download and install from nodejs.org.
  • npm: Comes with Node.js.
  • Basic knowledge of JavaScript and React: Familiarity with these concepts will help you understand the code

Setting Up the Project

Step 1: Create a new directory for your project

Open your terminal and run the following commands:

mkdir chat-app
cd chat-ap

Step 2: Initialize a new Node.js project

Create a package.json file:

npm init -y

Step 3: Install required packages

We need Express for the server, Socket.io for real-time communication, and CORS for handling cross-origin requests.

npm install express socket.io cors

Step 4: Set up the server

Create a file named server.js and add the following code:

const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const cors = require('cors');

const app = express();
const server = http.createServer(app);
const io = socketIO(server, {
    cors: {
        origin: 'http://localhost:3000', // Your React app URL
        methods: ['GET', 'POST'],
    },
});

app.use(cors());

// Object to store connected users and messages
let users = {};
let messages = [];

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

    // Handle user joining
    socket.on('join', (username) => {
        users[socket.id] = username;
        socket.broadcast.emit('userConnected', username);
        io.emit('userList', Object.values(users));
        console.log(`${username} joined the chat`);
    });

    // Handle sending messages
    socket.on('message', (message) => {
        messages.push({ user: users[socket.id], text: message });
        io.emit('message', { user: users[socket.id], text: message });
        console.log(`Message from ${users[socket.id]}: ${message}`);
    });

    // Handle disconnecting users
    socket.on('disconnect', () => {
        console.log('User disconnected:', socket.id);
        const username = users[socket.id];
        delete users[socket.id];
        socket.broadcast.emit('userDisconnected', username);
        io.emit('userList', Object.values(users));
    });
});

// Server listening on defined port
const PORT = process.env.PORT || 5000;
server.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

Frontend Development

Step 1: Set up the React application

Create a React app in the same directory:

npx create-react-app client
cd client

Step 2: Install Socket.io client

In the client directory, install the Socket.io client library:

npm install socket.io-client

Step 3: Create the chat application component

In the src directory, replace the contents of App.js with the following code:

import React, { useState, useEffect } from 'react';
import io from 'socket.io-client';
import './App.css';

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

function App() {
    const defaultUsername = 'Guest'; // Default username for all users
    const [message, setMessage] = useState('');
    const [chat, setChat] = useState([]);
    const [users, setUsers] = useState([]);

    useEffect(() => {
        // Automatically join the chat with default username
        socket.emit('join', defaultUsername);

        socket.on('message', (payload) => {
            setChat((prevChat) => [...prevChat, payload]);
        });

        socket.on('userList', (userList) => {
            setUsers(userList);
        });

        socket.on('userConnected', (username) => {
            setChat((prevChat) => [
                ...prevChat,
                { user: 'System', text: `${username} has joined the chat` },
            ]);
        });

        socket.on('userDisconnected', (username) => {
            setChat((prevChat) => [
                ...prevChat,
                { user: 'System', text: `${username} has left the chat` },
            ]);
        });

        return () => {
            socket.off();
        };
    }, []);

    const sendMessage = (e) => {
        e.preventDefault();
        if (message) {
            socket.emit('message', message);
            setMessage('');
        }
    };

    return (
        <div className="App">
            <div className="chat-container">
                <h2>Chat Room</h2>
                <div className="user-list">
                    <h3>Connected Users</h3>
                    <ul>
                        {users.map((user, idx) => (
                            <li key={idx}>{user}</li>
                        ))}
                    </ul>
                </div>

                <div className="chat-box">
                    {chat.map((message, index) => (
                        <div key={index} className="message">
                            <strong>{message.user}: </strong> {message.text}
                        </div>
                    ))}
                </div>

                <form onSubmit={sendMessage}>
                    <input
                        type="text"
                        value={message}
                        onChange={(e) => setMessage(e.target.value)}
                        placeholder="Type a message"
                        required
                    />
                    <button type="submit">Send</button>
                </form>
            </div>
        </div>
    );
}

export default App;

Step 4: Add CSS for styling

Create a new CSS file named App.css in the src directory and add the following styles:

body {
    font-family: 'Arial', sans-serif;
    background-color: #f5f5f5;
    margin: 0;
    padding: 20px;
}

.App {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    max-width: 800px;
    margin: auto;
}

.chat-container {
    width: 100%;
    padding: 20px;
    background: white;
    border-radius: 8px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

h2 {
    text-align: center;
}

.user-list {
    margin-bottom: 10px;
}

.user-list ul {
    list-style-type: none;
    padding: 0;
    margin: 0;
}

.chat-box {
    height: 300px;
    overflow-y: auto;
    border: 1px solid #ddd;
    border-radius: 5px;
    padding: 10px;
    background-color: #fafafa;
    margin-bottom: 10px;
}

.message {
    margin-bottom: 10px;
    padding: 5px;
    border-radius: 5px;
}

.message strong {
    color: #007BFF; /* Username color */
}

input[type="text"] {
    flex: 1;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
}

button {
    padding: 10px 15px;
    background-color: #007BFF;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

button:hover {
    background-color: #0056b3;
}

Testing the Application

Step 1: Run the backend server

In the terminal, navigate to your project directory and start the server:

node server.js

Step 2: Start the React app

In another terminal, navigate to the client directory and run:

npm start

Result

Once everything is set up and running, you should be able to open your browser and navigate to http://localhost:3000. You’ll see the chat interface, where you can type messages and see who is online.

Conclusion

In this blog post, we created a simple real-time chat application using Node.js and React. We covered setting up the server, managing socket connections, and creating the chat interface. This basic structure can be expanded with more features like user authentication, private messaging, and persistent chat history.

Feel free to experiment and enhance this application further! Happy coding!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top