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-socket-listener

v2.1.0

Published

Generic React hook for real-time event listening with any socket implementation (Socket.IO, WebSocket, etc.)

Readme

📡 react-socket-listener

A generic React hook for real-time event listening with any socket implementation (Socket.IO, WebSocket, etc.).
No more vendor lock-in! Works with Frappe/ERPNext, custom backends, or any real-time system.


🚀 Features

Generic & Flexible

  • 🔌 Works with any socket implementation (Socket.IO, WebSocket, custom)
  • 🎯 Zero dependencies - no vendor lock-in
  • 🔄 Backward compatible with existing Frappe/ERPNext projects

🛠 Advanced Features

  • 🔄 Auto-reconnection with exponential backoff
  • 📊 Connection statistics and monitoring
  • 🎛️ Event filtering and custom subscriptions
  • 🔁 Retry logic for failed operations
  • 🐛 Debug mode for development
  • 📈 Performance monitoring

🎯 Easy Integration

  • Simple React Hook API
  • 📦 Ready-to-use NPM package
  • 🔧 Built-in adapters for popular socket libraries
  • 📚 Comprehensive TypeScript support

📦 Installation

Easy Installation (Recommended)

npm install react-socket-listener
# or
yarn add react-socket-listener

If you encounter dependency conflicts:

npm install react-socket-listener --legacy-peer-deps
# or
yarn add react-socket-listener --legacy-peer-deps

Optional Dependencies

For Socket.IO support:

npm install socket.io-client

For Frappe/ERPNext support:

npm install frappe-react-sdk

Troubleshooting Installation Issues

If you're getting React version conflicts:

  1. Clear npm cache:

    npm cache clean --force
  2. Use legacy peer deps:

    npm install react-socket-listener --legacy-peer-deps
  3. Force installation (if needed):

    npm install react-socket-listener --force
  4. Check your React version:

    npm list react

    This package supports React 17, 18, and 19.


🛠 Usage

🆕 New Generic API (Recommended)

With Frappe Socket.IO

import React from "react";
import { useGenericEventListener, createSocketIOAdapter } from "react-socket-listener";
import { FrappeContext, FrappeConfig } from 'frappe-react-sdk';
import { useContext  } from "react";


function CustomerList() {
  // Create socket adapter
  const {socket} = useContext(FrappeContext) as FrappeConfig;
  
  const {
    viewers,
    socketStatus,
    isConnected,
    emitEvent,
    getStats
  } = useGenericEventListener(
    socket,
    { doctype: "Customer" },
    { 
      debug: true,
      autoReconnect: true,
      maxReconnectAttempts: 5
    },
    (event) => {
      console.log("📩 Incoming event:", event);
    }
  );

  return (
    <div>
      <h2>Customer Monitor</h2>
      <p>🔌 Status: {socketStatus} {isConnected ? "🟢" : "🔴"}</p>
      <p>👥 Viewers: {viewers.join(", ") || "None"}</p>
      <p>📊 Stats: {JSON.stringify(getStats())}</p>

      <button onClick={() => emitEvent("custom_event", { message: "Hello!" })}>
        🔔 Emit Event
      </button>
    </div>
  );
}

With Socket.IO

import React from "react";
import { useGenericEventListener, createSocketIOAdapter } from "react-socket-listener";

function CustomerList() {
  // Create socket adapter
  const socket = createSocketIOAdapter("http://localhost:8000");
  
  const {
    viewers,
    socketStatus,
    isConnected,
    emitEvent,
    getStats
  } = useGenericEventListener(
    socket,
    { doctype: "Customer" },
    { 
      debug: true,
      autoReconnect: true,
      maxReconnectAttempts: 5
    },
    (event) => {
      console.log("📩 Incoming event:", event);
    }
  );

  return (
    <div>
      <h2>Customer Monitor</h2>
      <p>🔌 Status: {socketStatus} {isConnected ? "🟢" : "🔴"}</p>
      <p>👥 Viewers: {viewers.join(", ") || "None"}</p>
      <p>📊 Stats: {JSON.stringify(getStats())}</p>

      <button onClick={() => emitEvent("custom_event", { message: "Hello!" })}>
        🔔 Emit Event
      </button>
    </div>
  );
}

With Native WebSocket

import React from "react";
import { useGenericEventListener, createWebSocketAdapter } from "react-socket-listener";

function RealTimeApp() {
  const socket = createWebSocketAdapter("ws://localhost:8080");
  
  const { socketStatus, emitEvent } = useGenericEventListener(
    socket,
    { doctype: "Orders", customEvents: ["order_updated", "payment_received"] },
    { debug: true }
  );

  return (
    <div>
      <p>Status: {socketStatus}</p>
      <button onClick={() => emitEvent("ping", { timestamp: Date.now() })}>
        Ping Server
      </button>
    </div>
  );
}

With Custom Socket Implementation

import React from "react";
import { useGenericEventListener, GenericSocket } from "react-socket-listener";

// Your custom socket implementation
class MyCustomSocket implements GenericSocket {
  connected = false;
  // ... implement all required methods
}

function CustomApp() {
  const socket = new MyCustomSocket();
  
  const { socketStatus, emitEvent } = useGenericEventListener(
    socket,
    { doctype: "Products" }
  );

  return <div>Status: {socketStatus}</div>;
}

🔄 Legacy API (Backward Compatible)

import React from "react";
import { useFrappeEventListener } from "react-socket-listener";

function CustomerList() {
  const { viewers, socketStatus, emitEvent } = useFrappeEventListener(
    "Customer",
    (event) => {
      console.log("📩 Incoming event:", event);
    }
  );

  return (
    <div>
      <h2>Customer Monitor</h2>
      <p>🔌 Socket status: {socketStatus}</p>
      <p>👥 Viewers: {viewers.join(", ") || "None"}</p>
    </div>
  );
}

Comparison

| Feature | Current frappeEventListener.tsx | react-socket-listener | |--------------------------|---------------------------------|---------------------------------------------------| | Socket Support | Frappe-specific only | ✅ Generic (Socket.IO, WebSocket, custom) | | Auto-reconnection | ❌ Basic | ✅ Advanced with exponential backoff | | Connection Monitoring | ❌ Basic status | ✅ Comprehensive stats & monitoring | | Event Filtering | ❌ None | ✅ Advanced filtering options | | Debug Mode | ❌ Commented out | ✅ Built-in debug logging | | Retry Logic | ❌ None | ✅ Configurable retry mechanism | | TypeScript Support | ❌ Basic | ✅ Full TypeScript definitions | | Performance Monitoring | ❌ None | ✅ Built-in performance stats | | Vendor Lock-in | ❌ Frappe-only | ✅ Zero dependencies, vendor-agnostic |

📚 API Reference

useGenericEventListener(socket, initialSubscription?, config?, onEventCallback?)

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | socket | GenericSocket \| null | ✅ | Socket instance (use adapters or implement GenericSocket) | | initialSubscription | SubscriptionOptions | ❌ | Initial subscription configuration | | config | EventListenerConfig | ❌ | Event listener configuration | | onEventCallback | function | ❌ | Callback for incoming events |

Returns

{
  viewers: string[];                                    // Active viewers
  socketStatus: SocketStatus;                          // Connection status
  isConnected: boolean;                                // Connection state
  emitEvent: (event: string, data?: any) => Promise<boolean>;  // Emit events
  subscribe: (options: SubscriptionOptions) => void;   // Subscribe to events
  unsubscribe: (doctype: string) => void;              // Unsubscribe
  getStats: () => ConnectionStats;                     // Get statistics
  reconnect: () => void;                               // Manual reconnect
  clearListeners: () => void;                          // Clear all listeners
}

Configuration Options

interface EventListenerConfig {
  autoReconnect?: boolean;           // Auto-reconnect on disconnect
  maxReconnectAttempts?: number;     // Max reconnection attempts
  reconnectDelay?: number;           // Delay between reconnects (ms)
  debug?: boolean;                   // Enable debug logging
  eventFilters?: {                   // Event filtering
    eventTypes?: string[];
    doctypes?: string[];
  };
  retryConfig?: {                    // Retry configuration
    maxAttempts?: number;
    delay?: number;
  };
}

🔧 Adapters

Socket.IO Adapter

import { createSocketIOAdapter, createFrappeSocketAdapter } from "react-socket-listener";

// Basic Socket.IO
const socket = createSocketIOAdapter("http://localhost:8000");

// Frappe-compatible Socket.IO
const frappeSocket = createFrappeSocketAdapter("http://localhost:8000", {
  token: "your-auth-token",
  userId: "[email protected]"
});

WebSocket Adapter

import { createWebSocketAdapter } from "react-socket-listener";

const socket = createWebSocketAdapter("ws://localhost:8080");

🎯 Use Cases

  • Frappe/ERPNext real-time updates
  • Custom backend real-time features
  • Multi-tenant applications
  • IoT device monitoring
  • Chat applications
  • Live dashboards
  • Collaborative editing

📄 Requirements

  • React ≥ 17
  • TypeScript (optional but recommended)

🐛 Common Issues & Solutions

Issue: "socket.io-client not found"

Solution: Install the optional dependency:

npm install socket.io-client

Issue: "frappe-react-sdk not found"

Solution: Install the optional dependency:

npm install frappe-react-sdk

Issue: React version conflicts

Solution: Use legacy peer deps:

npm install react-socket-listener --legacy-peer-deps

Issue: TypeScript errors

Solution: Make sure you have TypeScript installed:

npm install -D typescript @types/react

Issue: Socket connection fails

Solution: Check your server URL and ensure the server is running:

// Debug connection
const { debugInfo, connectionError } = useSocketConnection();
console.log('Debug info:', debugInfo);
console.log('Connection error:', connectionError);

🤝 Contributing

PRs and issues are welcome!
Please open an issue first to discuss what you'd like to change.


🛡 License

MIT © 2025 Abhishek-Chougule