use-realtime 1.0.1 โ 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 +369 -197
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,272 +11,444 @@ markdown
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
|
|
15
|
+
|
|
14
16
|
## โจ Features
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
-
|
|
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
|
+
|
|
23
35
|
|
|
24
36
|
---
|
|
25
37
|
|
|
38
|
+
|
|
39
|
+
|
|
26
40
|
## ๐ฆ Installation
|
|
27
41
|
|
|
42
|
+
### npm
|
|
43
|
+
```bash
|
|
44
|
+
npm install use-realtime
|
|
45
|
+
```
|
|
46
|
+
### yarn
|
|
47
|
+
```bash
|
|
48
|
+
yarn add use-realtime
|
|
49
|
+
```
|
|
50
|
+
### pnpm
|
|
28
51
|
```bash
|
|
29
|
-
|
|
52
|
+
pnpm add use-realtime
|
|
53
|
+
```
|
|
54
|
+
|
|
30
55
|
|
|
31
|
-
|
|
32
|
-
bash
|
|
56
|
+
## ๐ Quick Start
|
|
33
57
|
|
|
34
|
-
|
|
58
|
+
```jsx
|
|
59
|
+
import React, { useEffect } from 'react';
|
|
35
60
|
|
|
36
|
-
|
|
37
|
-
bash
|
|
61
|
+
import { useRealtime } from 'use-realtime';
|
|
38
62
|
|
|
39
|
-
|
|
63
|
+
|
|
40
64
|
|
|
41
|
-
|
|
42
|
-
jsx
|
|
65
|
+
function ChatComponent() {
|
|
43
66
|
|
|
44
|
-
|
|
45
|
-
import { useRealtime } from 'use-realtime';
|
|
46
|
-
|
|
47
|
-
function ChatComponent() {
|
|
48
|
-
const { emit, subscribe, isConnected } = useRealtime({
|
|
49
|
-
url: 'wss://your-server.com/ws',
|
|
50
|
-
autoReconnect: true,
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
const unsubscribe = subscribe('message', (data) => {
|
|
55
|
-
console.log('New message:', data);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
return unsubscribe; // Cleanup on unmount
|
|
59
|
-
}, [subscribe]);
|
|
60
|
-
|
|
61
|
-
const sendMessage = () => {
|
|
62
|
-
emit('chat', { text: 'Hello World!', user: 'You' });
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<div>
|
|
67
|
-
<p>Status: {isConnected ? 'โ
Connected' : 'โ Disconnected'}</p>
|
|
68
|
-
<button onClick={sendMessage} disabled={!isConnected}>
|
|
69
|
-
Send Message
|
|
70
|
-
</button>
|
|
71
|
-
</div>
|
|
72
|
-
);
|
|
73
|
-
}
|
|
67
|
+
const { emit, subscribe, isConnected } = useRealtime({
|
|
74
68
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
url: 'wss://your-server.com/ws',
|
|
70
|
+
|
|
71
|
+
autoReconnect: true,
|
|
72
|
+
|
|
73
|
+
});
|
|
78
74
|
|
|
79
|
-
interface RealtimeOptions {
|
|
80
|
-
// Required
|
|
81
|
-
url: string;
|
|
82
|
-
|
|
83
|
-
// Optional (with defaults)
|
|
84
|
-
autoConnect?: boolean; // Default: true
|
|
85
|
-
autoReconnect?: boolean; // Default: true
|
|
86
|
-
reconnectAttempts?: number; // Default: 10
|
|
87
|
-
reconnectInterval?: number; // Default: 3000 (ms)
|
|
88
75
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
+
|
|
95
89
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
90
|
+
|
|
91
|
+
const sendMessage = () => {
|
|
92
|
+
|
|
93
|
+
emit('chat', { text: 'Hello World!', user: 'You' });
|
|
94
|
+
|
|
95
|
+
};
|
|
96
|
+
|
|
101
97
|
|
|
102
|
-
|
|
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>
|
|
110
|
+
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
);
|
|
114
|
+
|
|
103
115
|
}
|
|
104
116
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
connect() Manually connect
|
|
112
|
-
disconnect() Manually disconnect
|
|
113
|
-
reconnect() Force reconnection
|
|
114
|
-
getQueueSize() Get number of queued messages
|
|
115
|
-
flushQueue() Clear all queued messages
|
|
116
|
-
clearSubscriptions() Remove all event listeners
|
|
117
|
-
State Property Type Description
|
|
118
|
-
isConnected boolean Connection is active
|
|
119
|
-
isConnecting boolean Connection in progress
|
|
120
|
-
isReconnecting boolean Reconnection in progress
|
|
121
|
-
connection ConnectionState Full connection details
|
|
122
|
-
Connection State Object
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## ๐ Documentation
|
|
120
|
+
|
|
121
|
+
### Configuration Options
|
|
122
|
+
|
|
123
123
|
typescript
|
|
124
124
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
125
|
+
```jsx
|
|
126
|
+
|
|
127
|
+
interface RealtimeOptions {
|
|
128
|
+
|
|
129
|
+
// Required
|
|
130
|
+
|
|
131
|
+
url: string;
|
|
132
|
+
|
|
133
|
+
// Optional (with defaults)
|
|
134
|
+
|
|
135
|
+
autoConnect?: boolean; // Default: true
|
|
136
|
+
|
|
137
|
+
autoReconnect?: boolean; // Default: true
|
|
138
|
+
|
|
139
|
+
reconnectAttempts?: number; // Default: 10
|
|
140
|
+
|
|
141
|
+
reconnectInterval?: number; // Default: 3000 (ms)
|
|
142
|
+
|
|
143
|
+
// Heartbeat configuration
|
|
144
|
+
|
|
145
|
+
heartbeat?: {
|
|
146
|
+
|
|
147
|
+
enabled?: boolean; // Default: false
|
|
148
|
+
|
|
149
|
+
interval?: number; // Default: 30000 (ms)
|
|
150
|
+
|
|
151
|
+
message?: any; // Default: 'ping'
|
|
152
|
+
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// Message queue for offline mode
|
|
156
|
+
|
|
157
|
+
messageQueue?: {
|
|
158
|
+
|
|
159
|
+
enabled?: boolean; // Default: true
|
|
160
|
+
|
|
161
|
+
maxSize?: number; // Default: 100
|
|
162
|
+
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
debug?: boolean; // Default: false
|
|
166
|
+
|
|
132
167
|
}
|
|
133
168
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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;
|
|
137
224
|
|
|
138
|
-
function ChatRoom() {
|
|
139
|
-
const [messages, setMessages] = useState([]);
|
|
140
|
-
const { subscribe, emit, isConnected } = useRealtime({
|
|
141
|
-
url: 'wss://chat-server.com/ws',
|
|
142
|
-
autoReconnect: true,
|
|
143
|
-
reconnectAttempts: 5,
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
useEffect(() => {
|
|
147
|
-
const unsubscribe = subscribe('chat-message', (msg) => {
|
|
148
|
-
setMessages(prev => [...prev, msg]);
|
|
149
|
-
});
|
|
150
|
-
return unsubscribe;
|
|
151
|
-
}, [subscribe]);
|
|
152
|
-
|
|
153
|
-
const sendMessage = (text) => {
|
|
154
|
-
emit('chat-message', { text, timestamp: Date.now() });
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
// ... render messages and input
|
|
158
225
|
}
|
|
159
226
|
|
|
160
|
-
|
|
161
|
-
|
|
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
|
+
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
return unsubscribe;
|
|
260
|
+
|
|
261
|
+
}, [subscribe]);
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
const sendMessage = (text) => {
|
|
266
|
+
|
|
267
|
+
emit('chat-message', { text, timestamp: Date.now() });
|
|
268
|
+
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
// ... render messages and input
|
|
162
274
|
|
|
163
|
-
function LiveDashboard() {
|
|
164
|
-
const [stats, setStats] = useState({});
|
|
165
|
-
const { subscribe } = useRealtime({
|
|
166
|
-
url: 'wss://api.example.com/live',
|
|
167
|
-
heartbeat: { enabled: true, interval: 15000 },
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
useEffect(() => {
|
|
171
|
-
const unsubscribe = subscribe('stats-update', (data) => {
|
|
172
|
-
setStats(data);
|
|
173
|
-
});
|
|
174
|
-
return unsubscribe;
|
|
175
|
-
}, [subscribe]);
|
|
176
|
-
|
|
177
|
-
// ... render dashboard with stats
|
|
178
275
|
}
|
|
179
276
|
|
|
180
|
-
|
|
181
|
-
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### 2. Live Dashboard
|
|
280
|
+
|
|
182
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 },
|
|
183
294
|
|
|
184
|
-
const { connect, disconnect, reconnect, isConnected } = useRealtime({
|
|
185
|
-
url: 'wss://example.com',
|
|
186
|
-
autoConnect: false, // Disable auto-connect
|
|
187
295
|
});
|
|
188
296
|
|
|
189
|
-
|
|
297
|
+
|
|
298
|
+
|
|
190
299
|
useEffect(() => {
|
|
191
|
-
|
|
300
|
+
|
|
301
|
+
const unsubscribe = subscribe('stats-update', (data) => {
|
|
302
|
+
|
|
303
|
+
setStats(data);
|
|
304
|
+
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
return unsubscribe;
|
|
308
|
+
|
|
309
|
+
}, [subscribe]);
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
// ... render dashboard with stats
|
|
314
|
+
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### ๐ง Advanced Usage
|
|
320
|
+
|
|
321
|
+
### Manual Connection Control
|
|
322
|
+
|
|
323
|
+
``` jsx
|
|
324
|
+
const { connect, disconnect, reconnect, isConnected } = useRealtime({
|
|
325
|
+
|
|
326
|
+
url: 'wss://example.com',
|
|
327
|
+
|
|
328
|
+
autoConnect: false, // Disable auto-connect
|
|
329
|
+
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
// Connect manually
|
|
335
|
+
|
|
336
|
+
useEffect(() => {
|
|
337
|
+
|
|
338
|
+
connect();
|
|
339
|
+
|
|
192
340
|
}, [connect]);
|
|
193
341
|
|
|
194
|
-
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
// Disconnect after 30 seconds
|
|
345
|
+
|
|
195
346
|
useEffect(() => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
347
|
+
|
|
348
|
+
const timer = setTimeout(() => {
|
|
349
|
+
|
|
350
|
+
if (isConnected) disconnect();
|
|
351
|
+
|
|
352
|
+
}, 30000);
|
|
353
|
+
|
|
354
|
+
return () => clearTimeout(timer);
|
|
355
|
+
|
|
200
356
|
}, [disconnect, isConnected]);
|
|
201
357
|
|
|
202
|
-
|
|
203
|
-
|
|
358
|
+
```
|
|
359
|
+
|
|
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
|
|
375
|
+
|
|
376
|
+
},
|
|
204
377
|
|
|
205
|
-
const { emit, getQueueSize, flushQueue } = useRealtime({
|
|
206
|
-
url: 'wss://example.com',
|
|
207
|
-
messageQueue: {
|
|
208
|
-
enabled: true,
|
|
209
|
-
maxSize: 50, // Queue up to 50 messages
|
|
210
|
-
},
|
|
211
378
|
});
|
|
212
379
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
// Messages are automatically queued when offline
|
|
216
383
|
|
|
217
|
-
//
|
|
218
|
-
|
|
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
|
|
219
397
|
|
|
220
|
-
// Clear queue if needed
|
|
221
398
|
flushQueue();
|
|
399
|
+
```
|
|
400
|
+
|
|
222
401
|
|
|
223
|
-
๐
|
|
224
|
-
Common Issues
|
|
402
|
+
### ๐ Troubleshooting
|
|
225
403
|
|
|
226
|
-
|
|
227
|
-
javascript
|
|
404
|
+
Common Issues
|
|
228
405
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
CORS Errors with Local Development
|
|
232
409
|
|
|
233
|
-
Connection Drops Frequently
|
|
234
410
|
javascript
|
|
411
|
+
```jsx
|
|
235
412
|
|
|
236
|
-
//
|
|
237
|
-
heartbeat: {
|
|
238
|
-
enabled: true,
|
|
239
|
-
interval: 15000, // Send ping every 15 seconds
|
|
240
|
-
}
|
|
413
|
+
// Ensure your WebSocket server allows connections from your origin
|
|
241
414
|
|
|
242
|
-
|
|
243
|
-
javascript
|
|
415
|
+
// For testing, use a public echo server:
|
|
244
416
|
|
|
245
|
-
|
|
246
|
-
reconnectAttempts: 5,
|
|
247
|
-
reconnectInterval: 5000, // Wait 5 seconds between attempts
|
|
417
|
+
url: 'wss://echo.websocket.org'
|
|
248
418
|
|
|
249
|
-
|
|
419
|
+
|
|
250
420
|
|
|
251
|
-
|
|
421
|
+
Connection Drops Frequently
|
|
252
422
|
|
|
253
|
-
|
|
423
|
+
javascript
|
|
254
424
|
|
|
255
|
-
|
|
425
|
+
|
|
256
426
|
|
|
257
|
-
|
|
427
|
+
// Enable heartbeat to keep connection alive
|
|
258
428
|
|
|
259
|
-
|
|
429
|
+
heartbeat: {
|
|
260
430
|
|
|
261
|
-
|
|
431
|
+
enabled: true,
|
|
262
432
|
|
|
263
|
-
|
|
433
|
+
interval: 15000, // Send ping every 15 seconds
|
|
264
434
|
|
|
265
|
-
|
|
266
|
-
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
267
438
|
|
|
268
|
-
|
|
439
|
+
### Too Many Reconnect Attempts
|
|
269
440
|
|
|
270
|
-
|
|
441
|
+
javascript
|
|
442
|
+
```jsx
|
|
443
|
+
// Limit reconnect attempts
|
|
271
444
|
|
|
272
|
-
|
|
445
|
+
reconnectAttempts: 5,
|
|
273
446
|
|
|
274
|
-
|
|
447
|
+
reconnectInterval: 5000, // Wait 5 seconds between attempts
|
|
448
|
+
```
|
|
449
|
+
|
|
275
450
|
|
|
276
|
-
๐ Links
|
|
277
451
|
|
|
278
|
-
|
|
452
|
+
|
|
279
453
|
|
|
280
|
-
npm Package
|
|
281
454
|
|
|
282
|
-
Issue Tracker
|
package/package.json
CHANGED