Introduction
Have you ever watched those live collaboration tools where you can see someone typing in real time and thought, "How does that work?" It's all about WebSockets, specifically Socket.IO.
Why do we need WebSockets?
Traditional web apps are like sending letters back and forth - you request something, wait for a response, and repeat. Not exactly the stuff of lightning-fast experiences, right?
Enter WebSockets: imagine having a phone call instead of sending letters. Both sides can talk whenever they want without waiting for the other to finish. That's the game-changer WebSockets bring to web development.
But raw WebSockets can be... finicky. That's why most developers reach for Socket.IO. It handles all the annoying stuff like:
- Automatically reconnecting when connections drop (because networks are never perfect)
- Broadcasting messages to multiple clients (essential for chat apps)
- Creating rooms and namespaces (think private vs. public chats)
- Adding middleware for things like authentication
Plus, it gracefully falls back to other methods when WebSockets aren't supported.
When Should You Actually Use Websockets?
Before we dive into code, let's be honest - not every app needs WebSockets. They're perfect when:
- Users need instant updates (think stock prices or sports scores)
- Communication flows both ways (like chat apps)
- Every millisecond of latency matters (multiplayer games)
- Your architecture is event-driven
If you're just building a blog or simple CRUD app, traditional HTTP requests will serve you just fine and save you some complexity.
Project Time!!!
Alright, enough theory - let's get our hands dirty! We'll create a simple real-time chat app with a Node.js backend and a React frontend.
Setting Up Our Backend
First, let's create a simple Socket.IO server:
mkdir socket-server
cd socket-server
npm init -y
npm install express socket.io cors
Now, let's create our index.js
file:
const express = require('express');
const http = require('http');
const cors = require('cors');
const { Server } = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: 'http://localhost:5173', // Vite's default port
methods: ['GET', 'POST']
}
});
io.on('connection', (socket) => {
console.log(`User connected: ${socket.id}`);
socket.on('send_message', (data) => {
io.emit('receive_message', data);
});
socket.on('disconnect', () => {
console.log('User disconnected');
});
});
server.listen(3001, () => {
console.log('Server is running on port 3001');
});
Pretty simple, right? When someone connects, we log it. When they send a message, we broadcast it to everyone. When they disconnect, we log that too.
Creating Our Frontend
Now for the fun part - create our React app using Vite:
npm create vite@latest socket-client --template react-ts
cd socket-client
npm install
npm install socket.io-client
Let's create a reusable socket connection in src/socket.ts
:
import { io } from 'socket.io-client';
const socket = io('http://localhost:3001');
export default socket;
And now for our chat interface in src/App.tsx
:
import { useEffect, useState } from 'react';
import socket from './socket';
interface Message {
message: string;
author: string;
}
function App() {
const [message, setMessage] = useState('');
const [author, setAuthor] = useState('');
const [messages, setMessages] = useState<Message[]>([]);
useEffect(() => {
socket.on('receive_message', (data: Message) => {
setMessages((prev) => [...prev, data]);
});
return () => {
socket.off('receive_message');
};
}, []);
const sendMessage = () => {
if (message && author) {
socket.emit('send_message', { message, author });
setMessage('');
}
};
return (
<div style={{ padding: '2rem' }}>
<h2>Chat Apph2>
<input
type="text"
placeholder="Enter Name"
value={author}
onChange={(e) => setAuthor(e.target.value)}
/>
<input
type="text"
placeholder="Enter Message"
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && sendMessage()}
/>
<button onClick={sendMessage}>Send Messagebutton>
<div>
{messages.map((msg, index) => (
<div key={index}>
<strong>{msg.author}:strong> {msg.message}
div>
))}
div>
div>
);
}
export default App;
Let's see the app in action
Let's fire everything up:
For the backend:
node index.js
For the frontend:
npm run dev
Now open http://localhost:5173
in a couple of browser tabs and start chatting. Watch as messages appear instantly across all tabs - that's the WebSocket magic happening!
What's Next?
This simple example just scratches the surface. Once you get comfortable with the basics, you might want to add:
- Private messaging rooms
- User authentication
- Message persistence with a database
- Typing indicators ("Sarah is typing...")
- Read receipts
The real-time possibilities are endless, and now you have the foundation to build them!
Conclusion
Whether you're creating the next big multiplayer game, a collaborative document editor, or just a super-responsive dashboard, Socket.IO and React make a powerful combo for bringing real-time features to life. If you like this blog and want to learn more about Frontend Development and Software Engineering, you can follow me on Dev.to.