Real-time Chat application under 5 minutes using NEXTJS and Socket.io
Let’s start the timer,
1. First, create a next app
npx create-next-app@latest
After creating the Next app, our project structure looks something like this.
2. Install the following dependencies
npm i socket.io socket.io-client
3. Now let's start to code,
go to pages/index.js file and copy the basic template.
import React, { useEffect, useState } from "react";
import io from "socket.io-client";
let socket;
const Home = () => {
useEffect(() => {
socketInitializer();
return () => {
socket.disconnect();
};
}, []);
async function socketInitializer() {
}
function handleSubmit(e) {
}
return (
<div>
<h1>Chat app</h1>
</div>
);
};
export default Home;
Whenever the component is mounted, socketInitializer() function is called and whenever the component is unmounted, we are disconnecting the socket connection. But where is the socket connection happening?
Before that let's set up the backend, here we use Nextjs which allows you to create APIs endpoints in a pages directory as though you’re writing backend code.
In pages/api we will create a new file called socket.js.
import { Server } from "socket.io";
export default function SocketHandler(req, res) {
const io = new Server(res.socket.server);
res.socket.server.io = io;
io.on("connection", (socket) => {
// after the connection.....
});
console.log("Setting up socket");
}
Now, when the client connects from the front end, the backend captures the connection even, with that we are creating a new socket.io server and assigning it to res.socket.server.io.
// Waits for a socket connection
io.on("connection", socket => {
// Each socket has a unique ID
// console.log(socket.id) -> ojIckSD2jqNzOqIrAGzL
})
Improving the code.
import { Server } from "socket.io";
export default function SocketHandler(req, res) {
if (res.socket.server.io) {
console.log("Already set up");
res.end();
return;
}
const io = new Server(res.socket.server);
res.socket.server.io = io;
io.on("connection", (socket) => {
socket.on("send-message", (obj) => {
io.emit("receive-message", obj);
});
});
console.log("Setting up socket");
res.end();
}
Now here, if a res.socket.server.io exist, then no need to create the socket.io server again, so we are simpling returning .
Inside the socket connection, we have created a listening event.
So what it does is, Adds the listener function to the end of the listener's array for the event named send-message (we call it as emit). So whenever a emit happens from the frontend with the event named send-message, then this event gets executed.
Inside it, we have an emitter named receive-message, which will emit the received object (obj) to the client side.
Now back to the client side, let’s connect to the backend.
import React, { useEffect, useState } from "react";
import io from "socket.io-client";
let socket;
const Home = () => {
useEffect(() => {
socketInitializer();
return () => {
socket.disconnect();
};
}, []);
async function socketInitializer() {
await fetch("/api/socket");
socket = io();
socket.on("receive-message", (data) => {
// we get the data here
});
}
function handleSubmit(e) {
}
return (
<div>
<h1>Chat app</h1>
</div>
);
};
export default Home;
We have initialized the socket by using the fetch(). This will create the socket server.
Next, we have an event listener which will listen if any emit is happening in the name receive-message.
Let's create a simple UI
import React, { useEffect, useState } from "react";
import io from "socket.io-client";
let socket;
const Home = () => {
const [message, setMessage] = useState("");
const [username, setUsername] = useState("");
useEffect(() => {
socketInitializer();
return () => {
socket.disconnect();
};
}, []);
async function socketInitializer() {
await fetch("/api/socket");
socket = io();
socket.on("receive-message", (data) => {
//
});
}
function handleSubmit(e) {
}
return (
<div>
<h1>Chat app</h1>
<h1>Enter a username</h1>
<input value={username} onChange={(e) => setUsername(e.target.value)} />
<br />
<br />
<div>
<form onSubmit={handleSubmit}>
<input
name="message"
placeholder="enter your message"
value={message}
onChange={(e) => setMessage(e.target.value)}
autoComplete={"off"}
/>
</form>
</div>
</div>
);
};
export default Home;
Username and a message box, the message box input field is wrapped inside the form. Whenever the form is submitted, we are calling the handleSubmit function.
Now let’s emit the message
import React, { useEffect, useState } from "react";
import io from "socket.io-client";
let socket;
const Home = () => {
const [message, setMessage] = useState("");
const [username, setUsername] = useState("");
const [allMessages, setAllMessages] = useState([]);
useEffect(() => {
socketInitializer();
return () => {
socket.disconnect();
};
}, []);
async function socketInitializer() {
await fetch("/api/socket");
socket = io();
socket.on("receive-message", (data) => {
setAllMessages((pre) => [...pre, data]);
});
}
function handleSubmit(e) {
e.preventDefault();
console.log("emitted");
socket.emit("send-message", {
username,
message
});
setMessage("");
}
return (
<div>
<h1>Chat app</h1>
<h1>Enter a username</h1>
<input value={username} onChange={(e) => setUsername(e.target.value)} />
<br />
<br />
<div>
{allMessages.map(({ username, message }, index) => (
<div key={index}>
{username}: {message}
</div>
))}
<br />
<form onSubmit={handleSubmit}>
<input
name="message"
placeholder="enter your message"
value={message}
onChange={(e) => setMessage(e.target.value)}
autoComplete={"off"}
/>
</form>
</div>
</div>
);
};
export default Home;
Inside the handleSubmit function, we have an emitter, that will emit a username and a message as an object to the send-message event listener in the backend. After it reaches the backend, we have another emitter inside the event listener (receive-message), which will emit back to the frontend.
Now the receive-message event listener gets the data.
socket.on("receive-message", (data) => {
setAllMessages((pre) => [...pre, data]);
});
All the above function happens Real-time to all the user’s currently using the application.
Go and play around with the code. Try creating a room for the user, refer to this doc.
All the codes are the in my GitHub. Check them out and STAR the repository if you have successfully completed the Chat Application.
GitHub - SarathAdhi/socket.io-starter-template: Created with CodeSandbox
Like and wait for an awesome project with socket.io and Nextjs.
Spoiler alert, the next app would be a game.
Top comments (0)