Reusable React Code Modules, Part 11 - Web Sockets
Real-Time Communication: Creating Reusable Web Socket Modules
WebSockets enable real-time, bidirectional communication between a client and server, crucial for applications that require live updates such as chat applications, live notifications, and real-time data feeds. This guide covers how to structure reusable WebSocket modules in React, manage real-time data efficiently, and integrate common WebSocket libraries.
Common Libraries and Tools
1. Socket.IO
Socket.IO is a popular library for real-time web applications, offering a simple and robust API
Key Features
Supports real-time bidirectional event-based communication
Automatic reconnection
Binary streaming
Supports namespaces and rooms
2. WebSocket API
The WebSocket API is a native JavaScript API for creating WebSocket connections
Key Features
Native browser support
Low-level API
Supports binary data transfer
3. ReconnectingWebSocket
ReconnectingWebSocket is a small library that provides automatic reconnection for WebSocket connections
Key Features
Automatic reconnection with configurable delay
Simple API
Compatible with the standard WebSocket API
4. StompJS
StompJS is a JavaScript client for the STOMP protocol, often used with message brokers like ActiveMQ or RabbitMQ.
Key Features
Supports the STOMP protocol
Works with many message brokers
Heart-beating and error handling
Comparison
Socket.IO: Best for comprehensive real-time communication with automatic reconnection and event-based API
WebSocket API: Ideal for projects requiring low-level WebSocket control with native browser support
ReconnectingWebSocket: Suitable for applications needing automatic reconnection without additional features
StompJS: Best for applications requiring STOMP protocol support and integration with message brokers
Examples
Example 1: Socket.IO
Setup:
import { io } from 'socket.io-client';
const socket = io('https://example.com', {
transports: ['websocket'],
reconnectionAttempts: 3,
reconnectionDelay: 1000,
});
export default socket;
Usage:
import React, { useEffect, useState } from 'react';
import socket from './socket';
const Chat = () => {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
useEffect(() => {
socket.on('message', (message) => {
setMessages((prevMessages) => [...prevMessages, message]);
});
return () => {
socket.off('message');
};
}, []);
const sendMessage = () => {
socket.emit('message', input);
setInput('');
};
return (
<div>
<ul>
{messages.map((msg, index) => (
<li key={index}>{msg}</li>
))}
</ul>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={sendMessage}>Send</button>
</div>
);
};
export default Chat;
Example 2: WebSocket API
Setup:
const createWebSocket = (url) => {
const socket = new WebSocket(url);
socket.onopen = () => {
console.log('WebSocket connection opened');
};
socket.onclose = () => {
console.log('WebSocket connection closed');
};
socket.onerror = (error) => {
console.error('WebSocket error:', error);
};
return socket;
};
export default createWebSocket;
Usage:
import React, { useEffect, useState } from 'react';
import createWebSocket from './webSocket';
const RealTimeData = () => {
const [data, setData] = useState([]);
const socket = createWebSocket('wss://example.com/socket');
useEffect(() => {
socket.onmessage = (event) => {
const message = JSON.parse(event.data);
setData((prevData) => [...prevData, message]);
};
return () => {
socket.close();
};
}, [socket]);
return (
<div>
<h1>Real-Time Data</h1>
<ul>
{data.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
};
export default RealTimeData;
Example 3: ReconnectingWebSocket
Setup:
import ReconnectingWebSocket from 'reconnecting-websocket';
const createReconnectingWebSocket = (url) => {
const socket = new ReconnectingWebSocket(url, [], {
reconnectInterval: 2000,
});
socket.onopen = () => {
console.log('Reconnecting WebSocket connection opened');
};
socket.onclose = () => {
console.log('Reconnecting WebSocket connection closed');
};
socket.onerror = (error) => {
console.error('Reconnecting WebSocket error:', error);
};
return socket;
};
export default createReconnectingWebSocket;
Usage:
import React, { useEffect, useState } from 'react';
import createReconnectingWebSocket from './reconnectingWebSocket';
const Notifications = () => {
const [notifications, setNotifications] = useState([]);
const socket = createReconnectingWebSocket('wss://example.com/notifications');
useEffect(() => {
socket.onmessage = (event) => {
const notification = JSON.parse(event.data);
setNotifications((prevNotifications) => [...prevNotifications, notification]);
};
return () => {
socket.close();
};
}, [socket]);
return (
<div>
<h1>Notifications</h1>
<ul>
{notifications.map((notification, index) => (
<li key={index}>{notification}</li>
))}
</ul>
</div>
);
};
export default Notifications;
Example 4: StompJS
Setup:
import Stomp from 'stompjs';
const createStompClient = (url) => {
const client = Stomp.client(url);
client.connect({}, () => {
console.log('Stomp client connected');
}, (error) => {
console.error('Stomp client error:', error);
});
return client;
};
export default createStompClient;
Usage:
import React, { useEffect, useState } from 'react';
import createStompClient from './stompClient';
const MessageBroker = () => {
const [messages, setMessages] = useState([]);
const client = createStompClient('ws://broker.example.com/stomp');
useEffect(() => {
client.connect({}, () => {
client.subscribe('/topic/messages', (message) => {
setMessages((prevMessages) => [...prevMessages, JSON.parse(message.body)]);
});
});
return () => {
client.disconnect();
};
}, [client]);
return (
<div>
<h1>Message Broker</h1>
<ul>
{messages.map((msg, index) => (
<li key={index}>{msg.content}</li>
))}
</ul>
</div>
);
};
export default MessageBroker;