react-socket-listener
v2.1.0
Published
Generic React hook for real-time event listening with any socket implementation (Socket.IO, WebSocket, etc.)
Maintainers
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-listenerIf you encounter dependency conflicts:
npm install react-socket-listener --legacy-peer-deps
# or
yarn add react-socket-listener --legacy-peer-depsOptional Dependencies
For Socket.IO support:
npm install socket.io-clientFor Frappe/ERPNext support:
npm install frappe-react-sdkTroubleshooting Installation Issues
If you're getting React version conflicts:
Clear npm cache:
npm cache clean --forceUse legacy peer deps:
npm install react-socket-listener --legacy-peer-depsForce installation (if needed):
npm install react-socket-listener --forceCheck your React version:
npm list reactThis 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-clientIssue: "frappe-react-sdk not found"
Solution: Install the optional dependency:
npm install frappe-react-sdkIssue: React version conflicts
Solution: Use legacy peer deps:
npm install react-socket-listener --legacy-peer-depsIssue: TypeScript errors
Solution: Make sure you have TypeScript installed:
npm install -D typescript @types/reactIssue: 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
