react-websocket-kit
v1.0.3
Published
A high-performance React WebSocket library with channel subscriptions, event-driven architecture, connection keep-alive, auto-reconnect, and UMD/CDN support.
Maintainers
Readme
react-websocket-kit
A high-performance React WebSocket client with channel/event pub-sub routing, heartbeat keep-alive, auto-reconnect with exponential backoff, and UMD/CDN support.
Features
- 🔌
useWebSockethook — Component-level WebSocket with full lifecycle control - 📡 Channel & Event Pub/Sub — Subscribe to structured
{ channel, event, payload }messages - 🔁 Auto-Reconnect — Exponential backoff with configurable attempts and max delay
- 💓 Heartbeat Keep-Alive — Detect dead connections and self-heal automatically
- 🌐 Shared Connections —
<WebSocketProvider>shares a single socket across your component tree - 📦 Dual Build — ESM (
import) and UMD (<script>tag) outputs - 🏷️ Full TypeScript — Ships
.d.tsdeclarations for every export
Installation
npm / yarn / pnpm
npm install react-websocket-kit
# or
yarn add react-websocket-kit
# or
pnpm add react-websocket-kitCDN (Script Tag)
<!-- React 18 (peer dependency) -->
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<!-- React WebSocket Kit -->
<script src="https://unpkg.com/react-websocket-kit/dist/index.umd.cjs"></script>
<script>
// All exports available on the global namespace:
const { useWebSocket, WebSocketProvider, useWebSocketEvent, ReadyState } = ReactWebSocketKit;
</script>Quick Start
1. Basic Hook Usage
Use useWebSocket for a single component-scoped connection:
import { useWebSocket, ReadyState } from 'react-websocket-kit';
function LiveStatus() {
const { readyState, sendRaw, lastMessage } = useWebSocket('ws://localhost:8080');
return (
<div>
<p>Status: {readyState === ReadyState.OPEN ? '🟢 Connected' : '🔴 Offline'}</p>
<button onClick={() => sendRaw('Hello Server!')}>Send</button>
<p>Last message: {lastMessage?.data}</p>
</div>
);
}2. Channel & Event Pub/Sub
All structured messages follow a standard envelope:
{
"channel": "chat:lobby",
"event": "new_message",
"payload": { "sender": "Alice", "text": "Hello!" }
}Emitting events
const { emit } = useWebSocket('ws://localhost:8080');
// Sends: {"channel":"chat:lobby","event":"new_message","payload":{"text":"Hi"}}
emit('chat:lobby', 'new_message', { text: 'Hi' });Subscribing to events (imperative)
const { subscribe } = useWebSocket('ws://localhost:8080');
useEffect(() => {
const unsubscribe = subscribe('chat:lobby', 'new_message', (payload) => {
console.log(payload.text);
});
return unsubscribe;
}, []);Subscribing to events (declarative hook)
import { useWebSocketEvent } from 'react-websocket-kit';
function ChatMessages() {
const [messages, setMessages] = useState([]);
// Auto-subscribes on mount, auto-unsubscribes on unmount
useWebSocketEvent('chat:lobby', 'new_message', (payload) => {
setMessages((prev) => [...prev, payload]);
});
return (
<ul>
{messages.map((m, i) => (
<li key={i}>{m.sender}: {m.text}</li>
))}
</ul>
);
}3. Shared Connection via Provider
Wrap your app in <WebSocketProvider> to share a single socket across all child components:
import { WebSocketProvider, useSharedWebSocket, useWebSocketEvent } from 'react-websocket-kit';
function App() {
return (
<WebSocketProvider url="ws://localhost:8080" options={{ heartbeat: true }}>
<Dashboard />
<Notifications />
</WebSocketProvider>
);
}
function Dashboard() {
const { emit, readyState } = useSharedWebSocket();
// emit(), sendRaw(), subscribe() all available here
}
function Notifications() {
useWebSocketEvent('alerts', 'new_alert', (payload) => {
alert(payload.message);
});
}API Reference
useWebSocket(url, options?)
The core hook. Returns a connection instance.
| Parameter | Type | Description |
|---|---|---|
| url | string \| () => string \| Promise<string> | WebSocket server URL or async resolver |
| options | WebSocketOptions | Configuration (see below) |
WebSocketOptions
| Option | Type | Default | Description |
|---|---|---|---|
| manual | boolean | false | If true, won't connect on mount — call connect() manually |
| reconnect | boolean \| ReconnectOptions | true | Auto-reconnect config (see below) |
| heartbeat | boolean \| HeartbeatOptions | false | Keep-alive config (see below) |
| queryParams | Record<string, string \| number \| boolean> | — | Appended to the connection URL |
| protocols | string \| string[] | — | WebSocket sub-protocols |
| onOpen | (event: Event) => void | — | Fires on connection open |
| onClose | (event: CloseEvent) => void | — | Fires on connection close |
| onMessage | (event: MessageEvent) => void | — | Fires on every raw incoming message |
| onError | (event: Event) => void | — | Fires on WebSocket error |
ReconnectOptions
| Option | Type | Default | Description |
|---|---|---|---|
| attempts | number | Infinity | Max reconnect attempts |
| delay | number | 2000 | Initial delay (ms) |
| maxDelay | number | 30000 | Maximum delay cap (ms) |
| exponential | boolean | true | Use exponential backoff |
HeartbeatOptions
| Option | Type | Default | Description |
|---|---|---|---|
| message | string \| object | 'ping' | Payload sent as keep-alive |
| interval | number | 30000 | How often to ping (ms) |
| timeout | number | 10000 | Time to wait for pong before closing (ms) |
| pongMessage | string \| object | — | Expected server response to reset timeout |
Return Value (UseWebSocketReturn)
| Property | Type | Description |
|---|---|---|
| readyState | ReadyState | Current connection state |
| lastMessage | MessageEvent \| null | Last raw message event received |
| sendRaw(data) | function | Send a raw string or binary payload |
| emit(channel, event, payload) | function | Send a structured { channel, event, payload } JSON message |
| subscribe(channel, event, cb) | function | Register a listener. Returns an unsubscribe function |
| unsubscribe(channel, event, cb) | function | Remove a specific listener |
| connect() | function | Manually open/reconnect the connection |
| disconnect() | function | Close the connection (prevents auto-reconnect) |
| getWebSocket() | function | Access the underlying WebSocket instance |
useWebSocketEvent(channel, event, callback, connection?)
Declarative hook that subscribes to a specific channel and event. Automatically cleans up on unmount.
useWebSocketEvent('orders', 'status_update', (payload) => {
console.log(`Order ${payload.orderId} is now ${payload.status}`);
});| Parameter | Type | Description |
|---|---|---|
| channel | string | Channel name to listen on |
| event | string | Event name to listen for |
| callback | (payload: T) => void | Handler called with the event payload |
| connection | UseWebSocketReturn | (Optional) Custom connection. If omitted, uses nearest <WebSocketProvider> |
<WebSocketProvider>
React context provider that creates and shares a single WebSocket connection.
<WebSocketProvider url="ws://localhost:8080" options={{ heartbeat: true }}>
{children}
</WebSocketProvider>| Prop | Type | Description |
|---|---|---|
| url | string \| () => string \| Promise<string> | WebSocket server URL |
| options | WebSocketOptions | Same options as useWebSocket |
useSharedWebSocket()
Access the shared connection created by the nearest <WebSocketProvider>. Returns the same UseWebSocketReturn shape as useWebSocket.
const { emit, readyState, subscribe, disconnect } = useSharedWebSocket();ReadyState Enum
| Value | Constant | Meaning |
|---|---|---|
| 0 | ReadyState.CONNECTING | Socket is connecting |
| 1 | ReadyState.OPEN | Connection is open and ready |
| 2 | ReadyState.CLOSING | Connection is closing |
| 3 | ReadyState.CLOSED | Connection is closed |
| -1 | ReadyState.UNINSTANTIATED | Hook mounted with manual: true, not yet connected |
Message Protocol
When using emit() and subscribe(), all messages are serialized as JSON with this structure:
interface WebSocketEventMessage<T = any> {
channel: string; // e.g. "chat:lobby", "market", "notifications"
event: string; // e.g. "new_message", "price_update", "alert"
payload: T; // any JSON-serializable data
}Server-side, parse incoming messages as JSON and route by channel + event. Messages that don't match this structure are still delivered to the onMessage callback and lastMessage — so raw text and binary payloads work seamlessly alongside structured events.
Example: Node.js Echo Server
import { WebSocketServer } from 'ws';
const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (data) => {
const msg = data.toString();
// Heartbeat
if (msg === 'ping') {
ws.send('pong');
return;
}
// Parse structured message
try {
const parsed = JSON.parse(msg);
const { channel, event, payload } = parsed;
// Broadcast to all clients
for (const client of wss.clients) {
if (client.readyState === 1) {
client.send(JSON.stringify({ channel, event, payload }));
}
}
} catch {
// Echo raw messages
ws.send(`Echo: ${msg}`);
}
});
});CDN Usage Example
A complete standalone HTML page using react-websocket-kit from a CDN:
<!DOCTYPE html>
<html>
<head>
<title>CDN WebSocket Demo</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://unpkg.com/react-websocket-kit/dist/index.umd.cjs"></script>
<script type="text/babel">
const { WebSocketProvider, useSharedWebSocket, useWebSocketEvent, ReadyState } = ReactWebSocketKit;
function Chat() {
const { emit, readyState } = useSharedWebSocket();
const [messages, setMessages] = React.useState([]);
useWebSocketEvent('chat', 'message', (payload) => {
setMessages(prev => [...prev, payload]);
});
const send = () => {
emit('chat', 'message', { text: 'Hello!', sender: 'CDN User' });
};
return (
<div>
<p>Status: {readyState === ReadyState.OPEN ? 'Connected' : 'Offline'}</p>
<button onClick={send} disabled={readyState !== ReadyState.OPEN}>Send</button>
<ul>
{messages.map((m, i) => <li key={i}>{m.sender}: {m.text}</li>)}
</ul>
</div>
);
}
function App() {
return (
<WebSocketProvider url="ws://localhost:8080">
<Chat />
</WebSocketProvider>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>TypeScript
All types are exported and available:
import type {
WebSocketOptions,
WebSocketEventMessage,
UseWebSocketReturn,
ReconnectOptions,
HeartbeatOptions,
EventListenerCallback,
WebSocketProviderProps,
} from 'react-websocket-kit';License
MIT
