Add real-time capabilities to your Next.js apps with WebSockets and modern patterns.
WebSocket Server with Next.js API Routes
// pages/api/socket.ts
import { Server } from 'socket.io';
import type { NextApiRequest, NextApiResponse } from 'next';
export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (!res.socket.server.io) {
const io = new Server(res.socket.server);
res.socket.server.io = io;
io.on('connection', (socket) => {
console.log('Client connected:', socket.id);
socket.on('message', (data) => {
// Broadcast to all clients
io.emit('message', data);
});
socket.on('disconnect', () => {
console.log('Client disconnected:', socket.id);
});
});
}
res.end();
}
Client-Side Integration
'use client';
import { useEffect, useState } from 'react';
import io, { Socket } from 'socket.io-client';
export function Chat() {
const [socket, setSocket] = useState<Socket | null>(null);
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState('');
useEffect(() => {
// Initialize socket connection
fetch('/api/socket');
const socketInstance = io();
socketInstance.on('connect', () => {
console.log('Connected to server');
});
socketInstance.on('message', (message: Message) => {
setMessages((prev) => [...prev, message]);
});
setSocket(socketInstance);
return () => {
socketInstance.disconnect();
};
}, []);
const sendMessage = () => {
if (socket && input.trim()) {
socket.emit('message', {
id: Date.now(),
text: input,
timestamp: new Date(),
});
setInput('');
}
};
return (
<div className="flex flex-col h-screen">
<div className="flex-1 overflow-y-auto p-4">
{messages.map((msg) => (
<div key={msg.id} className="mb-2">
<span className="font-bold">{msg.author}: </span>
{msg.text}
</div>
))}
</div>
<div className="p-4 border-t">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
className="w-full p-2 border rounded"
/>
</div>
</div>
);
}
Server-Sent Events (SSE)
// app/api/events/route.ts
export async function GET() {
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
const sendEvent = (data: any) => {
const message = `data: ${JSON.stringify(data)}\n\n`;
controller.enqueue(encoder.encode(message));
};
// Send updates every second
const interval = setInterval(() => {
sendEvent({ timestamp: new Date(), data: 'Update' });
}, 1000);
// Cleanup
setTimeout(() => {
clearInterval(interval);
controller.close();
}, 60000);
},
});
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
},
});
}
Custom Hook for WebSocket
import { useEffect, useRef, useState } from 'react';
export function useWebSocket<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [isConnected, setIsConnected] = useState(false);
const ws = useRef<WebSocket | null>(null);
useEffect(() => {
ws.current = new WebSocket(url);
ws.current.onopen = () => setIsConnected(true);
ws.current.onclose = () => setIsConnected(false);
ws.current.onmessage = (event) => {
setData(JSON.parse(event.data));
};
return () => ws.current?.close();
}, [url]);
const send = (data: any) => {
if (ws.current?.readyState === WebSocket.OPEN) {
ws.current.send(JSON.stringify(data));
}
};
return { data, isConnected, send };
}
Build engaging real-time features with these patterns!
Posted onnextjswith tags: