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 CHANGED
@@ -1,84 +1,162 @@
1
- # react-websocket [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/mehmetkose/react-websocket/edit/master/README.md) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmehmetkose%2Freact-websocket.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmehmetkose%2Freact-websocket?ref=badge_shield)
1
+ # react-websocket
2
2
 
3
- `react-websocket` is a easy-to-use React component for websocket communications.
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
- ## Help Wanted
5
+ [![npm](https://img.shields.io/npm/v/react-websocket.svg)](https://www.npmjs.com/package/react-websocket)
6
+ [![CI](https://github.com/mehmetkose/react-websocket/actions/workflows/ci.yml/badge.svg)](https://github.com/mehmetkose/react-websocket/actions/workflows/ci.yml)
7
+ [![bundle size](https://img.shields.io/bundlejs/size/react-websocket)](https://bundlejs.com/?q=react-websocket)
8
+ [![types](https://img.shields.io/npm/types/react-websocket.svg)](https://www.npmjs.com/package/react-websocket)
9
+ [![license](https://img.shields.io/npm/l/react-websocket.svg)](LICENSE)
10
+ [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmehmetkose%2Freact-websocket.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmehmetkose%2Freact-websocket?ref=badge_shield)
6
11
 
7
- Things here are running very slowly as I have a lot of other stuff to take care at the moment so please don't be upset if I don't answer your question or if a PR sits unreviewed for a few days or weeks. Anyone interested in helping it move faster can help by submitting or reviewing PR's and answering each other's questions.
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
- ### Installing
22
+ ## Install
11
23
 
24
+ ```sh
25
+ npm install react-websocket
12
26
  ```
13
- npm install --save react-websocket
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
- ### Usage
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
- ```js
19
- import React from 'react';
20
- import Websocket from 'react-websocket';
66
+ ```tsx
67
+ import { createWebSocket, useWebSocketEvent, useWebSocketStatus } from 'react-websocket';
21
68
 
22
- class ProductDetail extends React.Component {
69
+ export const chat = createWebSocket<ChatIn, ChatOut>('wss://api.example.com/chat', { json: true });
23
70
 
24
- constructor(props) {
25
- super(props);
26
- this.state = {
27
- count: 90
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
- handleData(data) {
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
- render() {
37
- return (
38
- <div>
39
- Count: <strong>{this.state.count}</strong>
85
+ ## Suspense
40
86
 
41
- <Websocket url='ws://localhost:8888/live/product/12345/'
42
- onMessage={this.handleData.bind(this)}/>
43
- </div>
44
- );
45
- }
46
- }
87
+ ```tsx
88
+ import { use, Suspense } from 'react';
47
89
 
48
- export default ProductDetail;
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
- ### Properties
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
- #### url
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
- **required**
56
- The url the websocket connection is listening to.
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
- #### onMessage
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
- **required**
61
- The callback called when data is received. Data is `JSON.parse`'d
129
+ ## Guides
62
130
 
63
- #### onOpen
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 callback called when the connection is successfully opened.
136
+ The docs source lives in [`docs/`](docs). Run `npm run docs:dev` to browse it locally.
66
137
 
67
- #### onClose
138
+ ## Compatibility
68
139
 
69
- The callback called when the connection is closed either due to server disconnect or network error.
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
- #### debug
146
+ ## Migrating from v2
72
147
 
73
- default: **false**
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
- #### reconnect
150
+ ## Example
77
151
 
78
- default: **true**
152
+ [`example/`](example) has a Tornado broadcast server and a Vite + React 19 client.
79
153
 
80
- accelerated reconnection time
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
  [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmehmetkose%2Freact-websocket.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmehmetkose%2Freact-websocket?ref=badge_large)