react-websocket 2.1.0 → 3.0.0
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 +127 -49
- package/dist/core.cjs +497 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +338 -0
- package/dist/core.d.ts +338 -0
- package/dist/core.js +469 -0
- package/dist/core.js.map +1 -0
- package/dist/index.cjs +129 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +418 -0
- package/dist/index.d.ts +418 -0
- package/dist/index.js +101 -0
- package/dist/index.js.map +1 -0
- package/package.json +112 -27
- package/build/index.js +0 -1344
- package/build/index.map +0 -1
- package/index.jsx +0 -106
- package/server.js +0 -18
- package/webpack.config.js +0 -35
- package/webpack.prod.config.js +0 -37
package/README.md
CHANGED
|
@@ -1,84 +1,162 @@
|
|
|
1
|
-
# react-websocket
|
|
1
|
+
# react-websocket
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Hooks-first WebSocket client for React 18 and 19.** Shared connections, automatic reconnects, a send queue, typed and validated messages, and Suspense, in about 2.5 kB with zero dependencies.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/react-websocket)
|
|
6
|
+
[](https://github.com/mehmetkose/react-websocket/actions/workflows/ci.yml)
|
|
7
|
+
[](https://bundlejs.com/?q=react-websocket)
|
|
8
|
+
[](https://www.npmjs.com/package/react-websocket)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fmehmetkose%2Freact-websocket?ref=badge_shield)
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
**[Documentation](https://mehmetkose.github.io/react-websocket/)** · [Getting started](https://mehmetkose.github.io/react-websocket/guide/getting-started) · [API](https://mehmetkose.github.io/react-websocket/api/) · [Recipes](https://mehmetkose.github.io/react-websocket/recipes) · [Changelog](CHANGELOG.md)
|
|
8
13
|
|
|
14
|
+
- **Shared connections.** Components using the same URL share one socket. StrictMode, `<Activity>` and route transitions never open duplicates.
|
|
15
|
+
- **Auto-reconnect.** Exponential backoff with jitter, plus an immediate retry when the browser comes back online or the tab becomes visible. Optional heartbeats detect dead links.
|
|
16
|
+
- **Send queue.** `send()` before the socket is open just works. The message goes out on connect.
|
|
17
|
+
- **Typed messages.** `json: true`, your own codec, or validation with any [Standard Schema](https://standardschema.dev) library (zod, valibot, arktype), with inferred types.
|
|
18
|
+
- **Suspense.** `use(client.ready)` waits for the first connection, and reconnects never flash a fallback.
|
|
19
|
+
- **SSR-safe.** Never connects during a server render, hydrates cleanly, and ships a `'use client'` entry for Next.js and other Server Components frameworks.
|
|
20
|
+
- **Small and typed.** Zero dependencies, ESM + CJS, TypeScript declarations with inline docs, plus a React-free `react-websocket/core` entry.
|
|
9
21
|
|
|
10
|
-
|
|
22
|
+
## Install
|
|
11
23
|
|
|
24
|
+
```sh
|
|
25
|
+
npm install react-websocket
|
|
12
26
|
```
|
|
13
|
-
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { useState } from 'react';
|
|
32
|
+
import { useWebSocket } from 'react-websocket';
|
|
33
|
+
|
|
34
|
+
type ChatIn = { user: string; text: string };
|
|
35
|
+
type ChatOut = { text: string };
|
|
36
|
+
|
|
37
|
+
function Chat() {
|
|
38
|
+
const [messages, setMessages] = useState<ChatIn[]>([]);
|
|
39
|
+
const { status, send } = useWebSocket<ChatIn, ChatOut>('wss://api.example.com/chat', {
|
|
40
|
+
json: true,
|
|
41
|
+
onMessage: message => setMessages(list => [...list, message])
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
<p>{status}</p>
|
|
47
|
+
<ul>
|
|
48
|
+
{messages.map((m, i) => (
|
|
49
|
+
<li key={i}>
|
|
50
|
+
{m.user}: {m.text}
|
|
51
|
+
</li>
|
|
52
|
+
))}
|
|
53
|
+
</ul>
|
|
54
|
+
<button onClick={() => send({ text: 'hi' })}>Say hi</button>
|
|
55
|
+
</>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
14
58
|
```
|
|
15
59
|
|
|
16
|
-
|
|
60
|
+
Handlers always see your latest props and state, and changing them never reconnects. `send`, `close` and `reconnect` keep the same identity between renders.
|
|
61
|
+
|
|
62
|
+
## Shared clients
|
|
63
|
+
|
|
64
|
+
Define a connection once and use it anywhere, including outside React:
|
|
17
65
|
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
import Websocket from 'react-websocket';
|
|
66
|
+
```tsx
|
|
67
|
+
import { createWebSocket, useWebSocketEvent, useWebSocketStatus } from 'react-websocket';
|
|
21
68
|
|
|
22
|
-
|
|
69
|
+
export const chat = createWebSocket<ChatIn, ChatOut>('wss://api.example.com/chat', { json: true });
|
|
23
70
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
71
|
+
function Messages() {
|
|
72
|
+
const [messages, setMessages] = useState<ChatIn[]>([]);
|
|
73
|
+
useWebSocketEvent(chat, 'message', m => setMessages(list => [...list, m])); // no re-render per message
|
|
74
|
+
return <ul>{/* … */}</ul>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function Header() {
|
|
78
|
+
const status = useWebSocketStatus(chat); // re-renders only when the status changes
|
|
79
|
+
return <button onClick={() => chat.send({ text: 'hi' })}>Say hi ({status})</button>;
|
|
80
|
+
}
|
|
81
|
+
```
|
|
30
82
|
|
|
31
|
-
|
|
32
|
-
let result = JSON.parse(data);
|
|
33
|
-
this.setState({count: this.state.count + result.movement});
|
|
34
|
-
}
|
|
83
|
+
The client connects when the first component uses it and closes a tick after the last one unmounts.
|
|
35
84
|
|
|
36
|
-
|
|
37
|
-
return (
|
|
38
|
-
<div>
|
|
39
|
-
Count: <strong>{this.state.count}</strong>
|
|
85
|
+
## Suspense
|
|
40
86
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
</div>
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
87
|
+
```tsx
|
|
88
|
+
import { use, Suspense } from 'react';
|
|
47
89
|
|
|
48
|
-
|
|
90
|
+
function Room() {
|
|
91
|
+
use(chat.ready); // React 19: suspend until the first connection
|
|
92
|
+
return <Messages />;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
<ErrorBoundary fallback={<Retry onClick={() => chat.reconnect()} />}>
|
|
96
|
+
<Suspense fallback={<Spinner />}>
|
|
97
|
+
<Room />
|
|
98
|
+
</Suspense>
|
|
99
|
+
</ErrorBoundary>;
|
|
49
100
|
```
|
|
50
101
|
|
|
51
|
-
|
|
102
|
+
`ready` stays resolved through automatic reconnects, so a network blip shows your `status` UI instead of replacing the page with a spinner. It rejects if the client gives up or `close()` is called.
|
|
103
|
+
|
|
104
|
+
## API at a glance
|
|
52
105
|
|
|
53
|
-
|
|
106
|
+
| Export | |
|
|
107
|
+
| --- | --- |
|
|
108
|
+
| `useWebSocket(url \| client, options?)` | Connect; returns `{ status, lastMessage, attempt, send, close, reconnect, client }` |
|
|
109
|
+
| `useWebSocketEvent(client, type, listener)` | Handle `'open'`, `'message'`, `'close'` or `'error'` without re-rendering |
|
|
110
|
+
| `useWebSocketStatus(client)` | The status; re-renders only when it changes |
|
|
111
|
+
| `createWebSocket(url, options?)` | A shareable client: `send`, `on`, `connect`, `close`, `reconnect`, `ready`, `getSnapshot`, `subscribe` |
|
|
112
|
+
| `MessageError` | Reported to `onError` when a message fails `parse` or `schema` |
|
|
54
113
|
|
|
55
|
-
|
|
56
|
-
|
|
114
|
+
| Option | Default | |
|
|
115
|
+
| --- | --- | --- |
|
|
116
|
+
| `protocols` | | Sub-protocols for the `WebSocket` constructor |
|
|
117
|
+
| `binaryType` | `'blob'` | |
|
|
118
|
+
| `json` | `false` | `JSON.parse` incoming and `JSON.stringify` outgoing messages |
|
|
119
|
+
| `parse(data)` / `serialize(message)` | | Custom codec; takes precedence over `json` |
|
|
120
|
+
| `schema` | | Standard Schema validation; types are inferred |
|
|
121
|
+
| `reconnect` | `true` | `false`, or `{ maxAttempts, minDelay, maxDelay, factor, jitter, shouldReconnect }` |
|
|
122
|
+
| `heartbeat` | | `{ interval, message, pong, timeout }` |
|
|
123
|
+
| `queue` | `true` | `false`, or `{ limit }` |
|
|
124
|
+
| `logger` | | e.g. `console.debug` |
|
|
125
|
+
| `WebSocket` | global | Custom implementation for tests or Node |
|
|
57
126
|
|
|
58
|
-
|
|
127
|
+
`useWebSocket` also takes `onOpen`, `onMessage`, `onClose`, `onError` and `enabled`. The [API reference](https://mehmetkose.github.io/react-websocket/api/) documents everything.
|
|
59
128
|
|
|
60
|
-
|
|
61
|
-
The callback called when data is received. Data is `JSON.parse`'d
|
|
129
|
+
## Guides
|
|
62
130
|
|
|
63
|
-
|
|
131
|
+
- [Shared clients](https://mehmetkose.github.io/react-websocket/guide/shared-clients) · [Messages and types](https://mehmetkose.github.io/react-websocket/guide/messages) · [Reconnecting and heartbeats](https://mehmetkose.github.io/react-websocket/guide/reconnecting)
|
|
132
|
+
- [Suspense](https://mehmetkose.github.io/react-websocket/guide/suspense) · [Server rendering and Next.js](https://mehmetkose.github.io/react-websocket/guide/ssr) · [StrictMode, Activity and lifecycle](https://mehmetkose.github.io/react-websocket/guide/lifecycle)
|
|
133
|
+
- [Authentication](https://mehmetkose.github.io/react-websocket/guide/authentication) · [Performance](https://mehmetkose.github.io/react-websocket/guide/performance) · [Testing](https://mehmetkose.github.io/react-websocket/guide/testing) · [Without React](https://mehmetkose.github.io/react-websocket/guide/without-react)
|
|
134
|
+
- [Recipes](https://mehmetkose.github.io/react-websocket/recipes) · [Troubleshooting](https://mehmetkose.github.io/react-websocket/troubleshooting) · [Migrating from v2](https://mehmetkose.github.io/react-websocket/migration)
|
|
64
135
|
|
|
65
|
-
The
|
|
136
|
+
The docs source lives in [`docs/`](docs). Run `npm run docs:dev` to browse it locally.
|
|
66
137
|
|
|
67
|
-
|
|
138
|
+
## Compatibility
|
|
68
139
|
|
|
69
|
-
|
|
140
|
+
| | |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| React | 18 and 19 (`use(client.ready)` needs 19; `<Activity>` is handled on 19.2+). Tested in CI against both |
|
|
143
|
+
| Runtimes | Modern browsers; Node via the `WebSocket` option |
|
|
144
|
+
| Frameworks | Vite, Next.js (App and Pages Router), Remix/React Router, Astro islands, and any React setup |
|
|
70
145
|
|
|
71
|
-
|
|
146
|
+
## Migrating from v2
|
|
72
147
|
|
|
73
|
-
|
|
74
|
-
Set to **true** to see console logging
|
|
148
|
+
v2 was a `<Websocket>` class component. v3 replaces it with hooks: `<Websocket url onMessage />` becomes `useWebSocket(url, { onMessage })`, and `ref.sendMessage(msg)` becomes `send(msg)`. See the [migration guide](https://mehmetkose.github.io/react-websocket/migration) for the full mapping.
|
|
75
149
|
|
|
76
|
-
|
|
150
|
+
## Example
|
|
77
151
|
|
|
78
|
-
|
|
152
|
+
[`example/`](example) has a Tornado broadcast server and a Vite + React 19 client.
|
|
79
153
|
|
|
80
|
-
|
|
154
|
+
## Contributing
|
|
81
155
|
|
|
156
|
+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md). To report a vulnerability, follow [SECURITY.md](SECURITY.md).
|
|
82
157
|
|
|
83
158
|
## License
|
|
159
|
+
|
|
160
|
+
[MIT](LICENSE)
|
|
161
|
+
|
|
84
162
|
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fmehmetkose%2Freact-websocket?ref=badge_large)
|