DEV Community

Cover image for How to Create a real-time chat application with WebSocket
Scofield Idehen
Scofield Idehen

Posted on • Originally published at blog.learnhub.africa

How to Create a real-time chat application with WebSocket

WebSockets are a technology for creating real-time, bi-directional communication channels over a single TCP connection.

They help build applications that require low-latency, high-frequency communication, such as chat applications, online gaming, and collaborative software.

In this tutorial, we will be building a real-time chat application using WebSockets and the Socket.IO library.

We will use Node.js as the server-side language and React as the client-side technology. However, the principles discussed in this tutorial can be applied to any language or technology that supports WebSockets.

Prerequisites

Before we begin, you should have the following prerequisites:

*Basic understanding of JavaScript
*Basic understanding of Node.js and React
*Basic understanding of web development concepts, such as *HTTP and HTML
*Node.js and npm installed on your machine
*React developer tools installed in your browser (optional, but helpful for debugging)

Setting up the Server

First, let's create a new directory for our project and navigate to it in the terminal.

mkdir real-time-chat-app
cd real-time-chat-app
Enter fullscreen mode Exit fullscreen mode

Next, let's create a new Node.js project by running the following command:

npm init -y

This will create a package.json file in our project directory.

Next, we need to install the Socket.IO library, which will handle the WebSocket communication for us. Run the following command to install it:

npm install socket.io

Now let's create a new file called server.js in the root of our project directory. This will be the entry point for our server-side code.

In server.js, we first need to require the http and socket.io modules:

const http = require('http');
const io = require('socket.io');

Next, let's create an HTTP server and bind it to a port. We will use port 3000 for this example, but you can choose any available port on your machine.

const server = http.createServer((req, res) => {

  res.end('Server is running!');
});
const port = 3000;
server.listen(port, () => {
  console.log(`Server is listening on port ${port}`);
});
Enter fullscreen mode Exit fullscreen mode

Now if we run the server by running node server.js in the terminal and navigate to http://localhost:3000 in the browser, we should see the message "Server is running!".

Next, we need to attach the Socket.IO server to our HTTP server. We do this by calling the listen method on the io object, and passing it our HTTP server as an argument:

const ioServer = io.listen(server);

Now that we have set up the server, let's move on to setting up the client-side code.

Setting up the Client

First, let's create a new directory called client in the root of our project directory. This is where we will store the client-side code for our chat application.

Next, let's create a new React project in the client directory. Run the following command in the client directory:

npm start

Once you have created a new React project in the client directory, you should have a public and src directory inside the client directory.

Inside the src directory, create a new file called App.js.

This will be the root component for our chat application.
First, let's import the required dependencies:

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

Next, let's create a function called useWebSocket that will handle the WebSocket communication for us.
This function will return an object with three properties:

messages: an array of messages that have been received from the server
sendMessage: a function that can be called to send a message to the server
error: an error object that will be set if there is an error in the WebSocket connection
Add the following code to App.js:

function useWebSocket() {

  const [messages, setMessages] = useState([]);
  const [error, setError] = useState(null);
  useEffect(() => {
    const socket = io('http://localhost:3000');
    socket.on('connect', () => {
      console.log('Connected to server!');
    });
    socket.on('disconnect', () => {
      console.log('Disconnected from server');
    });
    socket.on('error', (error) => {
      setError(error);
    });
    socket.on('message', (message) => {
      setMessages((prevMessages) => [...prevMessages, message]);
    });
    return () => {
      socket.disconnect();
    };
  }, []);
  const sendMessage = (message) => {
    if (socket.connected) {
      socket.send(message);
    }
  };
  return { messages, sendMessage, error };
}
Enter fullscreen mode Exit fullscreen mode

This code uses the useEffect hook to set up the WebSocket connection when the component mounts. We are also using the useState hook to keep track of the messages and error state.

The useWebSocket function returns an object that contains the messages array, the sendMessage function, and the error object.

Now let's use the useWebSocket function in our App component. Add the following code to App.js:

function App() {

  const { messages, sendMessage, error } = useWebSocket();
  if (error) {
    return <div>Error: {error.message}</div>;
  }
  return (
    <div>
      <ul>
        {messages.map((message) => (
          <li>{message}</li>
        ))}
      </ul>
      <form onSubmit={(event) => {
        event.preventDefault();
        const messageInput = event.target.elements.message;
        sendMessage(messageInput.value);
        messageInput.value = '';
      }}>
        <input name="message" />
        <button type="submit">Send</button>
function App() {
  const { messages, sendMessage, error } = useWebSocket();
  if (error) {
    return <div>Error: {error.message}</div>;
  }
  return (
    <div>
      <ul>
        {messages.map((message) => (
          <li>{message}</li>
        ))}
      </ul>
      <form onSubmit={(event) => {
        event.preventDefault();
        const messageInput = event.target.elements.message;
        sendMessage(messageInput.value);
        messageInput.value = '';
      }}>
        <input name="message" />
        <button type="submit">Send</button>
      </form>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Now let's move on to handling the messages on the server side.

Handling Messages on the Server
In the server.js file, let's add the following code to handle incoming messages:

ioServer.on('connection', (socket) => {

  console.log('New client connected');
  socket.on('message', (message) => {
    console.log(`Received message from client: ${message}`);
    ioServer.emit('message', message);
  });

  socket.on('disconnect', () => {
    console.log('Client disconnected');
  });
});
Enter fullscreen mode Exit fullscreen mode

In this code, we use the connection event to handle new clients connecting to the server. We are also using the message event to handle incoming messages from the client and the disconnect event to handle clients that disconnect from the server.

When a message is received, we simply log it to the console and then emit it back to all connected clients using the emit method.

Now, if you start the server by running node server.js and navigate to http://localhost:3000 in the browser, you should be able to send messages and see them displayed in real-time.

Conclusion

This tutorial taught us how to create a real-time chat application using WebSockets and the Socket.IO library. We have set up a Node.js server and a React client and implemented the WebSocket communication using the useWebSocket hook on the client side and the connection, message, and disconnect events on the server side.

You can extend this application in many ways, such as adding user authentication, storing messages in a database, and implementing more advanced features like message editing and deletion. I hope this tutorial has provided a good foundation for you to build upon.

Read more exciting articles on frontend here

Resource

Microsoft websockets
Basics of Websockets

Top comments (0)