Building Real-Time Apps with Next.js and WebSockets

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

Make sure to setup the project as shown below.

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

cd real-time-app
code .

Installing dependencies

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

npm install ws

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’);
});
});

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”
},

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.

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;

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;

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.

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.