Rabikant
Posted on November 23rd
How to build realtime chatroom with WebSocket using NextJS
"Lets learn How to build realtime chatroom with WebSocket using NextJS"
Let's create our app with:
npx create-next-app@latest example-app
Then cd into your app with:
cd example-app
Then name your app and configure it however you like.
After that, let's start by installing piesocket dependency:
npm i piesocket-js@5
Now let's install UUID
npm i uuid
Create an account on piehost.com after that you will be able to create a cluster there and get your api key and cluster id.
Importing modules and setup
This code imports the necessary modules for our app:
'use client';
import Head from 'next/head';
import { useState, useEffect } from 'react';
import PieSocket from 'piesocket-js';
import { v4 as uuidv4 } from 'uuid';
const ChatApp = () => {
};
next/head for the HTML head tags.
react for using React Hooks (useState, useEffect)
PieSocket for dealing with Real time communication
uuid for creating unique ID’s for the usernames.
The ChatApp component is defined as a function component.
Setting up state and PieSocket
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState('');
const [channel, setChannel] = useState(null);
const [username, setUsername] = useState(`User_${uuidv4().slice(0, 8)}`);
var pieSocket = new PieSocket({
clusterId: "your cluster id",
apiKey: "your api key",
notifySelf: true
});
This code sets up the initial state of the component using React's useState hook:
messages: A empty array for storing chats.
newMessage: a new empty array to hold the new message that is being typed.
channel: is set to null initially but will be set to the PieSocket channel momentarily
username: created using uuidv4 and it was assigned a username ( e.g., User_12345678).
The pieSocket instance is created with the required configuration:
clusterId: name of the PieSocket cluster
apiKey: the API key for the cluster of PieSocket
notifySelf: a flag to allow the current user to be notified by the system of his/her messages.
Setting up PieSocket
useEffect(() => {
pieSocket.subscribe("chat-room").then((channel) => {
console.log("Channel is ready");
setChannel(channel);
channel.listen("new_message", (data, meta) => {
console.log("New message: ", data);
setMessages((prevMessages) => [...prevMessages, data]);
});
});
}, []);
This code sets up the PieSocket channel using the useEffect hook:
On the initialization of the component, it connects to the “chat-room” channel utilizing pieSocket. subscribe
Once the channel is ready, it makes ‘channel’ to be equal to the name of the subscribed channel.
It then listens for new messages on the channel using channel.listen
When a new message is received, it alters the messages state by adding the new message to an existing array.
The third argument to the useEffect hook is an empty array [], so it will run the cleanup function only once, when the component is mounted.
Handling send message functionality
const handleSendMessage = () => {
if (!channel) return;
channel.publish("new_message", {
message: newMessage,
sender: username
});
setNewMessage('');
};
This code defines the handleSendMessage function, which is called when the user clicks the "Send" button:
It checks whether a channel is opened before running it.
If available, it publishes a new message to the channel using channel.publish
The newMessage text and the actions that have been made, as well as the username of the sender is included in the message object.
Finally, the code sets the newMessage state to the empty string once the message is sent as a submission to the server.
Rendering the chat interface
return (
<div className="h-screen flex flex-col items-center h-screen justify-end bg-gray-100">
<Head>
<title>Chat App</title>
</Head>
<ul className="list-none mb-4 flex flex-col items-center justify-center m-8">
{messages.map((message, index) => (
<li key={index} className="flex flex-wrap mb-2">
<span className="text-gray-700">{message.sender}: {message.message}</span>
</li>
))}
</ul>
<div className="flex justify-center mb-4">
<input
type="text"
value={newMessage}
onChange={(e) => setNewMessage(e.target.value)}
placeholder="Type a message..."
className="bg-white rounded-md p-2 text-gray-700"
/>
<button
onClick={handleSendMessage}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-md ml-2"
>
Send
</button>
</div>
</div>
);
This code returns the JSX elements that make up the chat interface:
The outermost container div with a gray color and with flex box used to layout the pieces.
Having a Head component to stipulate the page title
An Ul element to produce the layout of the chat messages.
Concrete each message is presented as the list item (li) with the username of the sender and the text of the message
An input field for typing new messages with type property value = newMessage and onChange event handler = handleChange
A “Send” button the execution of which leads to the call of the handleSendMessage function.
The chat interface is divided into three main sections: The labels of the fields incorporated in the modern messaging scheme are the message list, input field, and the send button.
This is the whole code for the app:
'use client';
import Head from 'next/head';
import { useState, useEffect } from 'react';
import PieSocket from 'piesocket-js';
import { v4 as uuidv4 } from 'uuid';
const ChatApp = () => {
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState('');
const [channel, setChannel] = useState(null);
const [username, setUsername] = useState(`User_${uuidv4().slice(0, 8)}`);
var pieSocket = new PieSocket({
clusterId: "your cluster id",
apiKey: "your api key",
notifySelf: true
});
useEffect(() => {
pieSocket.subscribe("chat-room").then((channel) => {
console.log("Channel is ready");
setChannel(channel);
channel.listen("new_message", (data, meta) => {
console.log("New message: ", data);
setMessages((prevMessages) => [...prevMessages, data]);
});
});
}, []);
const handleSendMessage = () => {
if (!channel) return;
channel.publish("new_message", {
message: newMessage,
sender: username
});
setNewMessage('');
};
return (
<div className="h-screen flex flex-col items-center justify-end bg-gray-100">
<Head>
<title>Chat App</title>
</Head>
<ul className="list-none mb-4 flex flex-col items-center justify-center m-8">
{messages.map((message, index) => (
<li key={index} className="flex flex-wrap mb-2">
<span className="text-gray-700">{message.sender}: {message.message}</span>
</li>
))}
</ul>
<div className="flex justify-center mb-4">
<input
type="text"
value={newMessage}
onChange={(e) => setNewMessage(e.target.value)}
placeholder="Type a message..."
className="bg-white rounded-md p-2 text-gray-700"
/>
<button
onClick={handleSendMessage}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-md ml-2"
>
Send
</button>
</div>
</div>
);
};
export default ChatApp;
Add this code in page.js and run your app with:
npm run dev

Complete Code
The project is available on our GitHub : https://github.com/piehostHQ/nextjs-ws-chatroom
