use-realtime 1.0.0 โ 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +371 -139
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,222 +1,454 @@
|
|
|
1
|
-
|
|
2
|
-
<div align="center">
|
|
1
|
+
markdown
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
https://img.shields.io/
|
|
3
|
+
# use-realtime ๐
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/use-realtime)
|
|
6
|
+
[](https://www.npmjs.com/package/use-realtime)
|
|
7
|
+
[](https://github.com/yaredabebe/use-realtime/blob/main/LICENSE)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
|
|
10
|
+
**Stop rewriting WebSocket boilerplate in every React project.** A production-ready React hook for building real-time features with auto-reconnect, message queuing, and event subscriptions.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## โจ Features
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
- **๐ Auto-reconnect** - Automatically reconnects with configurable retry limits
|
|
21
|
+
|
|
22
|
+
- **๐ฆ Message queue** - Never lose messages when offline (queues messages automatically)
|
|
23
|
+
|
|
24
|
+
- **๐ก Event-based API** - Simple subscribe/unsubscribe pattern for events
|
|
25
|
+
|
|
26
|
+
- **๐ Heartbeat support** - Optional ping-pong to keep connections alive
|
|
27
|
+
|
|
28
|
+
- **๐งน Automatic cleanup** - Proper cleanup on component unmount
|
|
29
|
+
|
|
30
|
+
- **๐ง TypeScript first** - Full type safety and IntelliSense support
|
|
31
|
+
|
|
32
|
+
- **โก Zero dependencies** - Lightweight and tree-shakable
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## ๐ฆ Installation
|
|
41
|
+
|
|
42
|
+
### npm
|
|
43
|
+
```bash
|
|
44
|
+
npm install use-realtime
|
|
45
|
+
```
|
|
46
|
+
### yarn
|
|
47
|
+
```bash
|
|
48
|
+
yarn add use-realtime
|
|
49
|
+
```
|
|
50
|
+
### pnpm
|
|
51
|
+
```bash
|
|
52
|
+
pnpm add use-realtime
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## ๐ Quick Start
|
|
57
|
+
|
|
58
|
+
```jsx
|
|
59
|
+
import React, { useEffect } from 'react';
|
|
60
|
+
|
|
61
|
+
import { useRealtime } from 'use-realtime';
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
function ChatComponent() {
|
|
66
|
+
|
|
67
|
+
const { emit, subscribe, isConnected } = useRealtime({
|
|
68
|
+
|
|
69
|
+
url: 'wss://your-server.com/ws',
|
|
70
|
+
|
|
71
|
+
autoReconnect: true,
|
|
72
|
+
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
|
|
79
|
+
const unsubscribe = subscribe('message', (data) => {
|
|
80
|
+
|
|
81
|
+
console.log('New message:', data);
|
|
82
|
+
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return unsubscribe; // Cleanup on unmount
|
|
86
|
+
|
|
87
|
+
}, [subscribe]);
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
const sendMessage = () => {
|
|
92
|
+
|
|
93
|
+
emit('chat', { text: 'Hello World!', user: 'You' });
|
|
94
|
+
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
|
|
101
|
+
<div>
|
|
102
|
+
|
|
103
|
+
<p>Status: {isConnected ? 'โ
Connected' : 'โ Disconnected'}</p>
|
|
104
|
+
|
|
105
|
+
<button onClick={sendMessage} disabled={!isConnected}>
|
|
106
|
+
|
|
107
|
+
Send Message
|
|
108
|
+
|
|
109
|
+
</button>
|
|
7
110
|
|
|
8
|
-
Stop rewriting WebSocket boilerplate in every React project
|
|
9
111
|
</div>
|
|
10
112
|
|
|
11
|
-
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## ๐ Documentation
|
|
120
|
+
|
|
121
|
+
### Configuration Options
|
|
122
|
+
|
|
123
|
+
typescript
|
|
124
|
+
|
|
125
|
+
```jsx
|
|
126
|
+
|
|
127
|
+
interface RealtimeOptions {
|
|
128
|
+
|
|
129
|
+
// Required
|
|
130
|
+
|
|
131
|
+
url: string;
|
|
132
|
+
|
|
133
|
+
// Optional (with defaults)
|
|
12
134
|
|
|
13
|
-
|
|
135
|
+
autoConnect?: boolean; // Default: true
|
|
14
136
|
|
|
15
|
-
|
|
137
|
+
autoReconnect?: boolean; // Default: true
|
|
16
138
|
|
|
17
|
-
|
|
139
|
+
reconnectAttempts?: number; // Default: 10
|
|
18
140
|
|
|
19
|
-
|
|
141
|
+
reconnectInterval?: number; // Default: 3000 (ms)
|
|
20
142
|
|
|
21
|
-
|
|
143
|
+
// Heartbeat configuration
|
|
22
144
|
|
|
23
|
-
|
|
145
|
+
heartbeat?: {
|
|
24
146
|
|
|
147
|
+
enabled?: boolean; // Default: false
|
|
25
148
|
|
|
149
|
+
interval?: number; // Default: 30000 (ms)
|
|
26
150
|
|
|
27
|
-
|
|
151
|
+
message?: any; // Default: 'ping'
|
|
28
152
|
|
|
29
|
-
|
|
30
|
-
๐ Auto-reconnect with retry limits
|
|
31
|
-
๐ฆ Message queue (no lost messages)
|
|
32
|
-
๐ก Event-based subscribe/unsubscribe API
|
|
33
|
-
๐ Optional heartbeat (keep connection alive)
|
|
34
|
-
๐งน Automatic cleanup on unmount
|
|
35
|
-
๐ง React-safe & TypeScript-first
|
|
36
|
-
๐ Works with any WebSocket backend
|
|
153
|
+
};
|
|
37
154
|
|
|
155
|
+
// Message queue for offline mode
|
|
38
156
|
|
|
39
|
-
|
|
157
|
+
messageQueue?: {
|
|
40
158
|
|
|
41
|
-
|
|
42
|
-
# or
|
|
43
|
-
yarn add use-realtime
|
|
44
|
-
# or
|
|
45
|
-
pnpm add use-realtime
|
|
159
|
+
enabled?: boolean; // Default: true
|
|
46
160
|
|
|
47
|
-
|
|
48
|
-
import { useRealtime } from 'use-realtime';
|
|
161
|
+
maxSize?: number; // Default: 100
|
|
49
162
|
|
|
50
|
-
|
|
51
|
-
const { emit, subscribe, isConnected } = useRealtime({
|
|
52
|
-
url: 'wss://example.com/ws',
|
|
53
|
-
autoReconnect: true,
|
|
54
|
-
});
|
|
163
|
+
};
|
|
55
164
|
|
|
56
|
-
//
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
const unsubscribe = subscribe('chat', (message) => {
|
|
59
|
-
console.log('New message:', message);
|
|
60
|
-
});
|
|
61
|
-
return unsubscribe;
|
|
62
|
-
}, [subscribe]);
|
|
165
|
+
debug?: boolean; // Default: false
|
|
63
166
|
|
|
64
|
-
return (
|
|
65
|
-
<button onClick={() => emit('chat', { text: 'Hello!' })}>
|
|
66
|
-
Send Message
|
|
67
|
-
</button>
|
|
68
|
-
);
|
|
69
167
|
}
|
|
70
168
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Hook Return Values
|
|
172
|
+
|
|
173
|
+
### Method Description
|
|
174
|
+
|
|
175
|
+
subscribe(event, callback) Subscribe to events, returns unsubscribe function
|
|
176
|
+
|
|
177
|
+
unsubscribe(event, callback) Unsubscribe from specific event
|
|
178
|
+
|
|
179
|
+
emit(event, data) Send event with data
|
|
180
|
+
|
|
181
|
+
send(data) Send raw data (auto-wrapped as 'message' event)
|
|
182
|
+
|
|
183
|
+
connect() Manually connect
|
|
184
|
+
|
|
185
|
+
disconnect() Manually disconnect
|
|
186
|
+
|
|
187
|
+
reconnect() Force reconnection
|
|
188
|
+
|
|
189
|
+
getQueueSize() Get number of queued messages
|
|
190
|
+
|
|
191
|
+
flushQueue() Clear all queued messages
|
|
192
|
+
|
|
193
|
+
clearSubscriptions() Remove all event listeners
|
|
194
|
+
|
|
195
|
+
State Property Type Description
|
|
196
|
+
|
|
197
|
+
isConnected boolean Connection is active
|
|
198
|
+
|
|
199
|
+
isConnecting boolean Connection in progress
|
|
200
|
+
|
|
201
|
+
isReconnecting boolean Reconnection in progress
|
|
202
|
+
|
|
203
|
+
connection ConnectionState Full connection details
|
|
204
|
+
|
|
205
|
+
### Connection State Object
|
|
206
|
+
|
|
207
|
+
typescript
|
|
208
|
+
|
|
209
|
+
```jsx
|
|
210
|
+
|
|
211
|
+
interface ConnectionState {
|
|
212
|
+
|
|
213
|
+
connected: boolean;
|
|
214
|
+
|
|
215
|
+
connecting: boolean;
|
|
216
|
+
|
|
217
|
+
reconnecting: boolean;
|
|
218
|
+
|
|
219
|
+
error: Error | null;
|
|
220
|
+
|
|
221
|
+
lastMessageAt: Date | null;
|
|
222
|
+
|
|
223
|
+
connectionId: string | null;
|
|
224
|
+
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## ๐ก Real-World Examples
|
|
230
|
+
|
|
231
|
+
### 1. Live Chat Application
|
|
232
|
+
|
|
233
|
+
```jsx
|
|
234
|
+
|
|
235
|
+
function ChatRoom() {
|
|
236
|
+
|
|
237
|
+
const [messages, setMessages] = useState([]);
|
|
238
|
+
|
|
239
|
+
const { subscribe, emit, isConnected } = useRealtime({
|
|
240
|
+
|
|
241
|
+
url: 'wss://chat-server.com/ws',
|
|
242
|
+
|
|
243
|
+
autoReconnect: true,
|
|
244
|
+
|
|
245
|
+
reconnectAttempts: 5,
|
|
246
|
+
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
|
|
253
|
+
const unsubscribe = subscribe('chat-message', (msg) => {
|
|
254
|
+
|
|
255
|
+
setMessages(prev => [...prev, msg]);
|
|
256
|
+
|
|
90
257
|
});
|
|
91
258
|
|
|
259
|
+
return unsubscribe;
|
|
260
|
+
|
|
261
|
+
}, [subscribe]);
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
const sendMessage = (text) => {
|
|
92
266
|
|
|
93
|
-
|
|
94
|
-
emit(event, data)
|
|
267
|
+
emit('chat-message', { text, timestamp: Date.now() });
|
|
95
268
|
|
|
96
|
-
|
|
97
|
-
emit('notification', { title: 'New order' });
|
|
269
|
+
};
|
|
98
270
|
|
|
271
|
+
|
|
99
272
|
|
|
100
|
-
|
|
273
|
+
// ... render messages and input
|
|
101
274
|
|
|
102
|
-
|
|
275
|
+
}
|
|
103
276
|
|
|
104
|
-
|
|
277
|
+
```
|
|
105
278
|
|
|
279
|
+
### 2. Live Dashboard
|
|
106
280
|
|
|
107
|
-
๐ Subscribing to Events
|
|
108
|
-
subscribe(event, callback)
|
|
109
281
|
jsx
|
|
282
|
+
```jsx
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
function LiveDashboard() {
|
|
286
|
+
|
|
287
|
+
const [stats, setStats] = useState({});
|
|
288
|
+
|
|
289
|
+
const { subscribe } = useRealtime({
|
|
290
|
+
|
|
291
|
+
url: 'wss://api.example.com/live',
|
|
292
|
+
|
|
293
|
+
heartbeat: { enabled: true, interval: 15000 },
|
|
110
294
|
|
|
111
|
-
const unsubscribe = subscribe('order:update', (data) => {
|
|
112
|
-
console.log(data);
|
|
113
295
|
});
|
|
114
296
|
|
|
115
|
-
|
|
297
|
+
|
|
298
|
+
|
|
116
299
|
useEffect(() => {
|
|
117
|
-
|
|
118
|
-
|
|
300
|
+
|
|
301
|
+
const unsubscribe = subscribe('stats-update', (data) => {
|
|
302
|
+
|
|
303
|
+
setStats(data);
|
|
304
|
+
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
return unsubscribe;
|
|
308
|
+
|
|
119
309
|
}, [subscribe]);
|
|
120
310
|
|
|
121
|
-
|
|
122
|
-
jsx
|
|
311
|
+
|
|
123
312
|
|
|
124
|
-
|
|
125
|
-
isConnected, // boolean - Connection is active
|
|
126
|
-
isConnecting, // boolean - Connection in progress
|
|
127
|
-
isReconnecting, // boolean - Reconnection in progress
|
|
128
|
-
connection, // Full connection object
|
|
129
|
-
} = useRealtime(...);
|
|
313
|
+
// ... render dashboard with stats
|
|
130
314
|
|
|
131
|
-
|
|
315
|
+
}
|
|
132
316
|
|
|
133
|
-
|
|
317
|
+
```
|
|
134
318
|
|
|
135
|
-
|
|
319
|
+
### ๐ง Advanced Usage
|
|
136
320
|
|
|
137
|
-
|
|
321
|
+
### Manual Connection Control
|
|
138
322
|
|
|
139
|
-
|
|
323
|
+
``` jsx
|
|
324
|
+
const { connect, disconnect, reconnect, isConnected } = useRealtime({
|
|
140
325
|
|
|
141
|
-
|
|
326
|
+
url: 'wss://example.com',
|
|
142
327
|
|
|
143
|
-
|
|
328
|
+
autoConnect: false, // Disable auto-connect
|
|
144
329
|
|
|
145
|
-
|
|
146
|
-
jsx
|
|
330
|
+
});
|
|
147
331
|
|
|
148
|
-
|
|
332
|
+
|
|
149
333
|
|
|
150
|
-
|
|
151
|
-
disconnect(); // Close connection safely
|
|
152
|
-
reconnect(); // Force reconnect
|
|
334
|
+
// Connect manually
|
|
153
335
|
|
|
154
|
-
|
|
155
|
-
jsx
|
|
336
|
+
useEffect(() => {
|
|
156
337
|
|
|
157
|
-
|
|
338
|
+
connect();
|
|
158
339
|
|
|
159
|
-
|
|
160
|
-
flushQueue(); // Clear queued messages
|
|
340
|
+
}, [connect]);
|
|
161
341
|
|
|
162
|
-
|
|
342
|
+
|
|
163
343
|
|
|
164
|
-
|
|
165
|
-
โ
Prevents duplicate connections
|
|
166
|
-
โ
Prevents reconnect loops
|
|
167
|
-
โ
Prevents memory leaks
|
|
344
|
+
// Disconnect after 30 seconds
|
|
168
345
|
|
|
169
|
-
|
|
346
|
+
useEffect(() => {
|
|
170
347
|
|
|
171
|
-
|
|
348
|
+
const timer = setTimeout(() => {
|
|
172
349
|
|
|
173
|
-
|
|
350
|
+
if (isConnected) disconnect();
|
|
174
351
|
|
|
175
|
-
|
|
352
|
+
}, 30000);
|
|
176
353
|
|
|
177
|
-
|
|
354
|
+
return () => clearTimeout(timer);
|
|
178
355
|
|
|
179
|
-
|
|
356
|
+
}, [disconnect, isConnected]);
|
|
180
357
|
|
|
181
|
-
|
|
358
|
+
```
|
|
182
359
|
|
|
183
|
-
|
|
184
|
-
|
|
360
|
+
### Message Queue (Offline Mode)
|
|
361
|
+
|
|
362
|
+
```jsx
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
const { emit, getQueueSize, flushQueue } = useRealtime({
|
|
367
|
+
|
|
368
|
+
url: 'wss://example.com',
|
|
369
|
+
|
|
370
|
+
messageQueue: {
|
|
371
|
+
|
|
372
|
+
enabled: true,
|
|
373
|
+
|
|
374
|
+
maxSize: 50, // Queue up to 50 messages
|
|
185
375
|
|
|
186
|
-
|
|
187
|
-
import type {
|
|
188
|
-
RealtimeOptions,
|
|
189
|
-
ConnectionState,
|
|
190
|
-
UseRealtimeReturn
|
|
191
|
-
} from 'use-realtime';
|
|
376
|
+
},
|
|
192
377
|
|
|
193
|
-
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
// Messages are automatically queued when offline
|
|
383
|
+
|
|
384
|
+
// and sent when connection is restored
|
|
385
|
+
|
|
386
|
+
emit('important-event', { data: 'will not be lost' });
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
// Check queue size
|
|
391
|
+
|
|
392
|
+
console.log('Queued messages:', getQueueSize());
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
// Clear queue if needed
|
|
194
397
|
|
|
195
|
-
|
|
398
|
+
flushQueue();
|
|
399
|
+
```
|
|
400
|
+
|
|
196
401
|
|
|
197
|
-
|
|
402
|
+
### ๐ Troubleshooting
|
|
198
403
|
|
|
199
|
-
|
|
404
|
+
Common Issues
|
|
200
405
|
|
|
201
|
-
|
|
406
|
+
|
|
202
407
|
|
|
203
|
-
|
|
408
|
+
CORS Errors with Local Development
|
|
204
409
|
|
|
205
|
-
|
|
410
|
+
javascript
|
|
411
|
+
```jsx
|
|
206
412
|
|
|
207
|
-
|
|
413
|
+
// Ensure your WebSocket server allows connections from your origin
|
|
208
414
|
|
|
209
|
-
|
|
415
|
+
// For testing, use a public echo server:
|
|
210
416
|
|
|
211
|
-
|
|
417
|
+
url: 'wss://echo.websocket.org'
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
Connection Drops Frequently
|
|
422
|
+
|
|
423
|
+
javascript
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
// Enable heartbeat to keep connection alive
|
|
428
|
+
|
|
429
|
+
heartbeat: {
|
|
430
|
+
|
|
431
|
+
enabled: true,
|
|
432
|
+
|
|
433
|
+
interval: 15000, // Send ping every 15 seconds
|
|
434
|
+
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
212
438
|
|
|
213
|
-
|
|
439
|
+
### Too Many Reconnect Attempts
|
|
214
440
|
|
|
215
|
-
|
|
216
|
-
|
|
441
|
+
javascript
|
|
442
|
+
```jsx
|
|
443
|
+
// Limit reconnect attempts
|
|
217
444
|
|
|
445
|
+
reconnectAttempts: 5,
|
|
218
446
|
|
|
447
|
+
reconnectInterval: 5000, // Wait 5 seconds between attempts
|
|
448
|
+
```
|
|
449
|
+
|
|
219
450
|
|
|
220
451
|
|
|
452
|
+
|
|
221
453
|
|
|
222
454
|
|
package/package.json
CHANGED