npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

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

  • 🔌 useWebSocket hook — 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.ts declarations for every export

Installation

npm / yarn / pnpm

npm install react-websocket-kit
# or
yarn add react-websocket-kit
# or
pnpm add react-websocket-kit

CDN (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