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

@arkosjs/react-websockets

v0.3.0

Published

React bindings for Arkos WebSocket Gateway

Readme

Header Image

npm npm GitHub

InstallationQuick StartAPI ReferenceExamplesDocumentationGitHub


What is @arkosjs/react-websockets?

React bindings for the Arkos WebSocket Gateway. Wraps @arkosjs/websockets-client in React hooks that integrate with your component lifecycle — no memory leaks, no listener churn, clean APIs.

Installation

npm install @arkosjs/react-websockets socket.io-client

You'll also need socket.io-client as a peer dependency.

Quick Start

1. Wrap your app with WebSocketProvider

import { Manager } from "socket.io-client";
import { WebSocketProvider } from "@arkosjs/react-websockets";

export default function App() {
  const [accessToken] = useState("123");

  const manager = useMemo(
    () =>
      new Manager("http://localhost:3000", {
        auth: { token: accessToken },
        reconnection: true,
      }),
    [accessToken]
  );

  return (
    <WebSocketProvider manager={manager}>
      <ChatRoom />
    </WebSocketProvider>
  );
}

The provider creates and owns the WebsocketClient. It's destroyed automatically on unmount.

2. Use useGateway in any child component

import { useGateway } from "@arkosjs/react-websockets";
import { useState } from "react";

function ChatRoom() {
  const chat = useGateway("/chat");
  const [messages, setMessages] = useState([]);

  // Listen to events — automatically cleaned up on unmount
  chat.on("receive_message", (data) => {
    setMessages((prev) => [...prev, data]);
  });

  // Emit with loading/error tracking
  const sendMessage = chat.useEmit("send_message");

  return (
    <div>
      <p>Status: {chat.status}</p>
      <button
        onClick={() =>
          sendMessage.emit({
            room: "general",
            content: "hello",
          })
        }
        disabled={sendMessage.loading}
      >
        {sendMessage.loading ? "Sending..." : "Send"}
      </button>
      {sendMessage.error && <p style={{ color: "red" }}>{sendMessage.error}</p>}
      <ul>
        {messages.map((msg, i) => (
          <li key={i}>{msg.content}</li>
        ))}
      </ul>
    </div>
  );
}

API Reference

<WebSocketProvider>

Provides the WebsocketClient to the React tree. Mount once at your app root.

<WebSocketProvider manager={manager}>{children}</WebSocketProvider>

| Prop | Type | Description | | ---------- | ----------------------------------- | ------------------------------------------------- | | manager | Manager (from socket.io-client) | Socket.IO manager with connection config and auth | | children | ReactNode | Your component tree |

The client is destroyed automatically when the provider unmounts.


useGateway(namespace)

Returns a scoped gateway handle for the given namespace. The underlying socket is lazily created on first call and reused.

const chat = useGateway("/chat");
const orders = useGateway("/orders");

Calling with the same namespace twice returns the same instance — no duplicate connections.

chat.on(event, handler, deps?)

Listen to a server event. Automatically unsubscribes on component unmount.

The handler is kept stable internally — changing the callback won't re-register the listener.

// Simple listener
chat.on("receive_message", (data) => {
  setMessages((prev) => [...prev, data]);
});

// With explicit dependencies (e.g., re-subscribe when room changes)
chat.on("receive_message", messageHandler, [roomId]);

Note: Client-side deduplication is applied automatically when _meta.mid is present in the payload.

chat.useEmit(event, defaultOptions?)

Returns a SocketEmitter object for the given event. Use it to emit with loading/error tracking.

const sendMessage = chat.useEmit("send_message");

// Fire and forget
sendMessage.emit({ room: "general", content: "hello" });

// With acknowledgement (waits for server response)
const result = await sendMessage.emit(data, {
  ack: true,
  timeout: 5000,
  retries: 3,
});

if (result.success) {
  console.log("Message sent:", result.data);
} else {
  console.error("Failed:", result.error);
}

SocketEmitter properties:

  • emit(data, options?) — Emit the event. Returns void for fire-and-forget, Promise for ack.
  • loadingboolean — True while waiting for ack response.
  • errorstring | null — Last error message, or null if succeeded.
  • lastEmittedAtnumber | null — Timestamp of last emit, or null if never emitted.
  • reset() — Clears error and loading state.

chat.status

Reactive connection status. Re-renders when status changes.

chat.status; // "connected" | "connecting" | "reconnecting" | "disconnected"

if (chat.status === "connected") {
  sendMessage.emit(data);
}

chat.raw

Escape hatch to the underlying GatewayClient for advanced use cases.

chat.raw; // GatewayClient instance
chat.raw.rawSocket; // raw socket.io Socket

useWebsocketClient()

Returns the WebsocketClient instance from context. Throws if used outside <WebSocketProvider>.

const client = useWebsocketClient();
const gateway = client.gateway("/notifications");

Examples

Handle Authentication

Listen for the "authenticated" event after login:

function Dashboard() {
  const chat = useGateway("/chat");
  const [user, setUser] = useState(null);

  useEffect(() => {
    // Server emits "authenticated" with user data
    chat.on("authenticated", (data) => {
      setUser(data.user);
    });
  }, [chat]);

  return user ? <div>Welcome, {user.name}</div> : <div>Loading...</div>;
}

Emit with Acknowledgement

function SendForm() {
  const chat = useGateway("/messages");
  const sendMessage = chat.useEmit("send_message");

  const handleSubmit = async (e) => {
    e.preventDefault();
    const result = await sendMessage.emit(
      { content: "Hello!" },
      { ack: true, timeout: 5000, retries: 2 }
    );

    if (result.success) {
      alert("Message received by server");
    } else {
      alert(`Error: ${result.error}`);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <button disabled={sendMessage.loading}>
        {sendMessage.loading ? "Sending..." : "Send"}
      </button>
    </form>
  );
}

Global Error Handler

Listen for server-wide errors:

function ChatRoom() {
  const chat = useGateway("/chat");

  chat.on("error", (errorData) => {
    console.error("Server error:", errorData);
    // Show toast, log, etc.
  });

  return <div>Chat App</div>;
}

Watch Connection Status

function ConnectionIndicator() {
  const chat = useGateway("/chat");

  return (
    <div
      style={{
        color:
          chat.status === "connected"
            ? "green"
            : chat.status === "disconnected"
              ? "red"
              : "orange",
      }}
    >
      {chat.status}
    </div>
  );
}

Types

import type {
  ArkosEmitOptions,
  ArkosEmitResult,
  ArkosEventHandler,
  GatewayStatus,
  SocketEmitter,
} from "@arkosjs/react-websockets";

| Type | Description | | --------------------------------- | ----------------------------------------------------------------- | | GatewayStatus | "connected" \| "connecting" \| "reconnecting" \| "disconnected" | | ArkosEventHandler<T> | (data: T) => void | | ArkosEmitOptions | { ack?: boolean; timeout?: number; retries?: number } | | ArkosEmitResult<T> | { success: boolean; data?: T; error?: string } | | SocketEmitter<TData, TResponse> | Return type of chat.useEmit() |


Peer Dependencies

| Package | Version | | ---------------------------- | ---------- | | react | >=17.0.0 | | socket.io-client | ^4.7.0 | | @arkosjs/websockets-client | * |


Related


License

MIT

InstallationQuick StartAPI ReferenceExamplesDocumentationGitHub

Built with ❤️ as part of Arkos.js

Real-time React, simplified.