DEV Community

Cover image for Building Real-Time Apps with Next.js and WebSockets
Daniel Musembi
Daniel Musembi

Posted on

Building Real-Time Apps with Next.js and WebSockets

Introduction

In today's fast-paced digital world, real-time data exchange is essential for developing dynamic and interactive web applications. WebSockets are a powerful method for enabling real-time, bidirectional communication between clients and servers. In this blog post, we'll look at how to use WebSockets with Next.js to create real-time apps.

A WebSocket is a communication protocol that provides full-duplex communication channels over a single TCP connection. It enables a real-time, event-driven connection between a client and a server.

Unlike traditional HTTP software, which follows a request-response model, WebSockets allow two-way (bi-directional) communication. This means that the client and the server can send data to each other anytime without continuous polling. To learn more about WebSocket check here. Without further ado, let's get started developing our real-time communication application. We'll start by bootstrapping a new Next.js project.

Open your preferred code editor and run the following command on the terminal to create a new project.

 npx create-next-app@latest real-time-app
Enter fullscreen mode Exit fullscreen mode

Make sure to setup the project as shown below.

Image description

After it has finished, run the following commands to open the projects folder in the code editor.

cd real-time-app
code .
Enter fullscreen mode Exit fullscreen mode

Installing dependencies

Run the following command to install ws a WebSocket library for Node.js.

npm install ws
Enter fullscreen mode Exit fullscreen mode

Creating a WebSocket server

Let's start by creating server.js file in the root directory and insert the following code in it.

 const { createServer } = require('http');
 const { parse } = require('url');
 const next = require('next');
 const WebSocket = require('ws');

 const dev = process.env.NODE_ENV !== 'production';
 const app = next({ dev });
 const handle = app.getRequestHandler();

 app.prepare().then(() => {
     const server = createServer((req, res) => {
         const parsedUrl = parse(req.url, true);
         handle(req, res, parsedUrl);
     });

     const wss = new WebSocket.Server({ server });

     wss.on('connection', (ws) => {
         console.log('New client connected');

         ws.on('message', (message) => {
             console.log(`Received message: ${message}`);
             ws.send(`Server: ${message}`);
         });

         ws.on('close', () => {
             console.log('Client disconnected');
         });
     });

     server.listen(3000, (err) => {
         if (err) throw err;
         console.log('> Ready on http://localhost:3000');
     });
 });
Enter fullscreen mode Exit fullscreen mode

In this code, we set up a server. It first imports the necessary modules and sets up a Next.js app in development mode if NODE_ENV is not set to 'production'. The app prepares the server to handle HTTP requests with Next.js's request handler. It also creates a WebSocket server (wss) attached to the HTTP server.

When a WebSocket client connects, the server logs the connection. It listens for messages from the client, logs them, and sends back a response. It also logs when the client disconnects. The server listens on port 3000.

Next, modify the Script in the package.json file to use the custom server we've just created.

  "scripts": {
    "dev": "node server.js",
    "build": "next build",
    "start": "NODE_ENV=production node server.js"
},
Enter fullscreen mode Exit fullscreen mode

Integrating WebSocket client in Next.js

In this part, we will create a WebSocket client in our Next.js application. Begin by creating a hooks folder in the app directory.
Then, create a file called useWebSocket.js.

Image description

Insert the following code in that file

 import { useEffect, useState } from 'react';

 const useWebSocket = (url) => {
     const [messages, setMessages] = useState([]);
     const [ws, setWs] = useState(null);

     useEffect(() => {
         const socket = new WebSocket(url);
         setWs(socket);

         socket.onmessage = (event) => {
             setMessages((prevMessages) => [...prevMessages, event.data]);
         };

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

     const sendMessage = (message) => {
         if (ws) {
             ws.send(message);
         }
     };

     return { messages, sendMessage };
 };

 export default useWebSocket;
Enter fullscreen mode Exit fullscreen mode

In this code we define a custom React hook useWebSocket for managing WebSocket connections. It establishes a connection to a WebSocket server using the provided URL, stores incoming messages in a state array, and provides a function to send messages through the WebSocket.

useEffect: Opens a WebSocket connection when the component mounts and closes it when the component unmounts.

onmessage: Updates the messages state with incoming messages.

sendMessage: Sends a message through the WebSocket if it's connected.
The hook returns the messages array and the sendMessage function for use in components.

Using the WebSocket in a component

To use WebSocket in our component, update the page.js file with the following code.

'use client'

import { useState } from 'react';
import useWebSocket from '@/app/hooks/useWebSocket';

const Home = () => {
    const { messages, sendMessage } = useWebSocket('ws://localhost:4000');
    const [input, setInput] = useState('');

    const handleSubmit = (e) => {
        e.preventDefault();
        sendMessage(input);
        setInput('');
    };

    return (
        <div>
            <h1>Real-time Chat</h1>
            <form onSubmit={handleSubmit}>
                <input
                    type="text"
                    value={input}
                    onChange={(e) => setInput(e.target.value)}
                />
                <button type="submit">Send</button>
            </form>
            <div>
                {messages.map((msg, index) => (
                    <div key={index}>{msg}</div>
                ))}
            </div>
        </div>
    );
};

export default Home;
Enter fullscreen mode Exit fullscreen mode

This is a React component for our real-time chat functionality using WebSockets. The component leverages React's useState hook to manage the state of the input field, allowing users to type and send messages.

Key Features:

  • WebSocket Integration: Utilizes a custom useWebSocket hook to establish a WebSocket connection to ws://localhost:4000.

  • State Management: Uses useState to handle the current message input.

  • Message Handling: The handleSubmit function sends the typed message via WebSocket and then clears the input field.

  • Real-time Updates: Displays received messages in real-time by mapping over the messages array.

How It Works:

  • Connection: On component mount, useWebSocket initiates a WebSocket connection.

  • Sending Messages: When the form is submitted, sendMessage sends the message, and the input field is reset.

  • Displaying Messages: Received messages are displayed dynamically as they arrive.

Running the application

Run the following command on the terminal to start the application. Open your browser and navigate to http://localhost:3000. You should see a simple chat interface where you can send messages and receive real-time updates.

Image description

Conclusion

Finally, developing real-time applications with Next.js and WebSockets is an effective way to improve user experiences through instant communication and updates. This post demonstrates how to set up a WebSocket server and a Next.js application to create a smooth real-time chat interface. Using these technologies, developers may incorporate dynamic, interactive features into their online applications, paving the way for more engaging and responsive user engagements. This method not only increases functionality but also lays the groundwork for future real-time application development.

Top comments (0)