https://github.com/maxzinchenko/react-use-socket
The package which makes web socket management much easier by using hooks.
https://github.com/maxzinchenko/react-use-socket
react react-use-socket socket websocket
Last synced: 2 months ago
JSON representation
The package which makes web socket management much easier by using hooks.
- Host: GitHub
- URL: https://github.com/maxzinchenko/react-use-socket
- Owner: maxzinchenko
- License: mit
- Created: 2022-01-07T21:29:45.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2022-05-05T18:34:10.000Z (about 4 years ago)
- Last Synced: 2025-09-30T16:42:12.970Z (9 months ago)
- Topics: react, react-use-socket, socket, websocket
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/react-use-socket
- Size: 659 KB
- Stars: 2
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# React Use Socket
The package which makes web socket management much easier by using hooks.
The package is built over the WebSocket constructor from browser API.
---
## Structure
- [Installation](#installation)
- [One socket example](https://github.com/maxzinchenko/react-use-socket/blob/master/example/src/one-socket.tsx)
- [Multiple sockets example](https://github.com/maxzinchenko/react-use-socket/blob/master/example/src/many-sockets.tsx)
- [Provider options](#provider-options)
- [url](#url)
- [getRequestIndicator](#getRequestIndicator)
- [getResponseIndicator](#getResponseIndicator)
- [getError](#getError)
- [autoConnect](#autoConnect)
- [protocols](#protocols)
- [shouldReconnect](#shouldReconnect)
- [reconnectionIntervals](#reconnectionInterval)
- [serialize](#serialize)
- [deserialize](#deserialize)
- [debug](#debug)
- [Hooks usage](#hooks-usage)
- [useWebSocketState](#useWebSocketState)
- [useSignal](#useSignal)
- [useLazySignal](#useLazySignal)
- [useSubscription](#useSubscription)
- [useLazySubscription](#useLazySubscription)
- [Custom Error Type](#custom-error-type)
- [Provider options declaration](#provider-options-declaration)
- [Passing own types to WebSocketOptions type](#passing-own-types-to-websocketoptions-type)
---
## Installation
```
# using npm
npm install react-use-socket
# using yarn
yarn add react-use-socket
```
---
## Provider options
`WebSocketOptions`
| Name | Required | Type | Default |
| ------------------------------------------------- | -------- | --------------------------------------------------- | ----------- |
| [url](#url) | Yes | `string` | - |
| [getRequestIndicator](#getRequestIndicator) | Yes | `(req: Req) => string OR number` | - |
| [getResponseIndicator](#getResponseIndicator) | Yes | `(res: Res) => string OR number` | - |
| [getError](#getError) | Yes | `(res: Res) => string OR Err OR null` | - |
| [autoConnect](#autoConnect) | No | `boolean` | `true` |
| [protocols](#protocols) | No | `string OR string[]` | - |
| [shouldReconnect](#shouldReconnect) | No | `((event: CloseEvent) => boolean) OR boolean` | `true` |
| [reconnectionIntervals](#reconnectionInterval) | No | `number OR number[]` | `1000` |
| [serialize](#serialize) | No | `(req: Req) => SReq` | - |
| [deserialize](#deserialize) | No | `(res: Res) => DRes` | - |
| [debug](#debug) | No | `boolean` | - |
---
## url (required)
`string`
Url for the WebSocket constructor.
```ts
url: 'ws://localhost:3000'
```
```ts
url: 'wss://example.com'
```
## getRequestIndicator (required)
`(res: Res) => string | number`
**WARNING:** Make sure that the `getRequestIndicator(req)` value indicator is exactly same as `getResponseIndicator(res)`.
The package needs to know which the request received response belongs to.
Let us say that the request which needs to be sent to the API looks as:
**(this is just an example it's not a requirement to the API request type)**
```ts
req = {
get_user: {
id: 1
}
}
```
The indicator is `get_user` so the prop should be:
```ts
getRequestIndicator: req => Object.keys(req)[0]
```
## getResponseIndicator (required)
`(res: Res) => string | number`
**WARNING:** Make sure that the `getResponseIndicator(res)` value indicator is exactly same as `getRequestIndicator(req)`.
The package needs to know which the request received response belongs to.
Let us say that the response which comes from the API and needs to be handled looks as:
**(this is just an example it's not a requirement to the API response type)**
```ts
res = {
get_user: {
id: 1,
username: '@...',
avatarUrl: 'https://...'
}
}
```
The indicator is `get_user` so the prop should be:
```ts
getResponseIndicator: req => Object.keys(req)[0]
```
## getError (required)
`(res: Res) => string | Err | null`
Let us say that the failure response which comes from the API looks as:
**(this is just an example it's not a requirement to the API response type)**
```ts
res = {
get_user: {
error: 'Not found'
}
}
```
The error is `Not found` so the prop should be:
```ts
getError: res => res[Object.keys(req)[0]].error || null
```
When using custom error type `Err`:
(see doc of the [Custom error type](#Custom error type))
```ts
res = {
get_user: {
error: {
message: 'Not found',
meta: {...}
}
}
}
```
The error is an `object` so the prop should be:
```ts
getError: res => res[Object.keys(req)[0]].error || null
```
## autoConnect
`boolean` - (`true` by default)
When `true` you don't need to send anything to connect it.
When `false` you need to connect the socket manually by using `useWebSocketState` hook.
```ts
autoConnect: true
```
## shouldReconnect
`((event: CloseEvent) => boolean) | boolean` - (`true` by default)
When `true` the socket tries to reconnect if `event.code !== 1005`.
When the predicate is passed you are able to decide if the socket needs to be reconnected.
```ts
shouldReconnect: true
```
## debug
`boolean`
When `true` the package shows additional logs.
```ts
debug: ture
```
## protocols
`boolean`
Protocols for the WebSocket constructor.
```ts
protocols: 'some protocol'
```
```ts
protocols: ['some protocol']
```
## reconnectionInterval
`number | number[]` - (`1000` by default)
In milliseconds.
When array each new connection uses the next number from the array for a timeout to avoid DDOSing a server.
```ts
reconnectionInterval: 1000
```
When reconnection count reaches the last array element it uses it each the next time.
When the socket connects back the next reconnection loop will start from the `0` index.
```ts
reconnectionInterval: [0, 1000, 2000, 3000, 4000, 5000, 10000]
```
## serialize
`(req: Req) => SReq`
`Req` and `SReq` are templates of the generic `MiddlewareOptions` type
The format function gets called to prepare the data to get submitted to the server. For example, `camelCase` to `snake_case` conversion.
```ts
serialize: req => {
return {
...req,
time: Date.now()
}
}
```
## deserialize
`(res: Res) => DRes`
`Res` and `DRes` are templates of the generic `MiddlewareOptions` type
The format function gets called to prepare the message to get submitted to the `onMessage` callback. For example, `snake_case` to `camelCase` conversion.
```ts
deserialize: res => {
return res.data
}
```
---
## Custom Error Type
```ts
enum Socket {
MAIN = 'Main'
}
type Req = {
get_user: {
id: number
}
}
type DRes = {
get_user: {
username: string
avatarUrl: string
}
}
type Error = {
message: string
meta: {
timestamp: number
service: string
...
}
}
```
Putting these types into a generic hook:
```ts
const signalData = useSignal({...})
```
```ts
const [signalData, signalControls] = useLazySignal()
```
```ts
const [subscriptionData, subscriptionControls] = useSubscription('')
```
```ts
const [subscriptionData, subscriptionControls] = useLazySubscription('')
```
---
## Hooks usage
### useWebSocketState
When you use only one socket, passing the socket name is optional.
```tsx
import React from 'react';
import { useWebSocketState } from 'react-awesome-websocket';
const Component = () => {
const [connected, { open, close }] = useWebSocketState();
return (
<>
useWebSocketState example
Connected: {connected}
Open
Close
<>
);
};
```
When you use multiple sockets, passing the socket name is required. Otherwise, you get the
`The "name" is required for the hook usage` error.
```tsx
import React from 'react';
import { useWebSocketState } from 'react-awesome-websocket';
enum Socket {
MAIN = 'Main'
}
const Component = () => {
const [connected, { open, close }] = useWebSocketState({ name: Socket.MAIN });
return (
<>
useWebSocketState example
Connected: {connected}
Open
Close
<>
);
};
```
### useSignal
When you use only one socket, passing the socket name is optional.
```tsx
import React from 'react';
import { useSignal } from 'react-awesome-websocket';
type Req = {
get_user: {
id: number
}
}
type Res = {
get_user: {
username: string
avatarUrl: string
}
}
const Component = () => {
const { loading, error, data, mounted } = useSignal({
get_user: { id: 1 }
});
return (
<>
useSignal example
Loading: {loading}
Error: {error}
Mounted: {mounted}
Data:
{JSON.stringify(data, null, 4)}
<>
);
};
```
When you use multiple sockets, passing the socket name is required. Otherwise, you get the
`The "name" is required for the hook usage` error.
```tsx
import React from 'react';
import { useSignal } from 'react-awesome-websocket';
enum Socket {
MAIN = 'Main'
}
type Req = {
get_user: {
id: number
}
}
type Res = {
get_user: {
username: string
avatarUrl: string
}
}
const Component = () => {
const { loading, error, data, mounted } = useSignal({
get_user: { id: 1 }
}, { name: Socket.MAIN });
return (
<>
useSignal example
Loading: {loading}
Error: {error}
Mounted: {mounted}
Data:
{JSON.stringify(data, null, 4)}
<>
);
};
```
### useLazySignal
When you use only one socket, passing the socket name is optional.
```tsx
import React from 'react';
import { useLazySignal } from 'react-awesome-websocket';
type Req = {
get_user: {
id: number
}
}
type DRes = {
get_user: {
username: string
avatarUrl: string
}
}
const Component = () => {
const [signalData, { send }] = useLazySignal({
get_user: { id: 1 }
});
const { loading, error, data, mounted } = signalData;
const handleSendClick = () => {
send({ get_user: { id: 1 } });
}
return (
<>
useLazySignal example
Send Request
Loading: {loading}
Error:
{JSON.stringify(error, null, 4)}
Mounted: {mounted}
Data:
{JSON.stringify(data, null, 4)}
<>
);
};
```
When you use multiple sockets, passing the socket name is required. Otherwise, you get the
`The "name" is required for the hook usage` error.
```tsx
import React from 'react';
import { useLazySignal } from 'react-awesome-websocket';
enum Socket {
MAIN = 'Main'
}
type Req = {
get_user: {
id: number
}
}
type DRes = {
get_user: {
username: string
avatarUrl: string
}
}
const Component = () => {
const [signalData, { send }] = useLazySignal({
get_user: { id: 1 }
}, { name: Socket.MAIN });
const { loading, error, data, mounted } = signalData;
const handleSendClick = () => {
send({ get_user: { id: 1 } });
}
return (
<>
useLazySignal example
Send Request
Loading: {loading}
Error:
{JSON.stringify(error, null, 4)}
Mounted: {mounted}
Data:
{JSON.stringify(data, null, 4)}
<>
);
};
```
### useSubscription
When you use only one socket, passing the socket name is optional.
```tsx
import React from 'react';
import { useSubscription } from 'react-awesome-websocket';
type DRes = {
user_update: {
username: string
avatarUrl: string
}
}
const Component = () => {
const [{ data, error }, { stop }] = useSubscription('user_update');
return (
<>
useSubscription example
Stop subscription
Error: {error}
Data:
{JSON.stringify(data, null, 4)}
<>
);
};
```
When you use multiple sockets, passing the socket name is required. Otherwise, you get the
`The "name" is required for the hook usage` error.
```tsx
import React from 'react';
import { useSubscription } from 'react-awesome-websocket';
enum Socket {
MAIN = 'Main'
}
type DRes = {
user_update: {
username: string
avatarUrl: string
}
}
const Component = () => {
const [{ data, error }, { stop }] = useSubscription('user_update', {
name: Socket.MAIN
});
return (
<>
useSubscription example
Stop subscription
Error: {error}
Data:
{JSON.stringify(data, null, 4)}
<>
);
};
```
### useLazySubscription
When you use only one socket, passing the socket name is optional.
```tsx
import React from 'react';
import { useLazySubscription } from 'react-awesome-websocket';
type Req = {
get_user: {
id: number
}
}
type DRes = {
get_user: {
username: string
avatarUrl: string
}
}
const Component = () => {
const [{ data, error }, { start, stop }] = useLazySubscription('user_update');
return (
<>
useLazySubscription example
Start subscription
Stop subscription
Error: {error}
Data:
{JSON.stringify(data, null, 4)}
<>
);
};
```
When you use multiple sockets, passing the socket name is required. Otherwise, you get the
`The "name" is required for the hook usage` error.
```tsx
import React from 'react';
import { useLazySubscription } from 'react-awesome-websocket';
enum Socket {
MAIN = 'Main'
}
type Req = {
get_user: {
id: number
}
}
type DRes = {
get_user: {
username: string
avatarUrl: string
}
}
const Component = () => {
const [{ data, error }, { start, stop }] = useLazySubscription('user_update', {
name: Socket.MAIN
});
return (
<>
useLazySubscription example
Start subscription
Stop subscription
Error: {error}
Data:
{JSON.stringify(data, null, 4)}
<>
);
};
```
---
## Provider options declaration
```ts
import { WebSocketOptions } from 'react-awesome-websocket';
enum Scoket {
MAIN = 'Main'
};
type ScoketReq = {
method: string
data: Record
};
type SocketRes = {
[method: string]: Record
};
type ScoketSerializedReq = {
[method: string]: Record
};
type SocketDeserializedRes = Record;
type SocketError = {
message: string
meta: {}
};
const options: WebSocketOptions<
ScoketReq,
SocketRes,
Scoket,
SocketError,
ScoketSerializedReq,
SocketDeserializedRes
> = {
[Socket.MAIN]: {
url: 'ws://localhost:3000',
getRequestIndicator: req => req.method,
getResponseIndicator: res => Object.keys(res)[0],
getError: res => res[Object.keys(res)[0]].error_msg || null,
// serialize: (req: ScoketReq) => ScoketSerializedReq
serialize: ({ method, data }) => ({ [method]: data }),
// deserialize: (res: SocketRes) => SocketDeserializedRes
deserialize: (res: SocketRes) => res[Object.keys(res)[0]]
}
};
```
### Passing own types to WebSocketOptions type
`WebSocketOptions` is a generic type.
```ts
WebSocketOptions
```
`Req` - type of the socket request (required).
`Res` - type of the socket response (required).
`N` (default is `string`) - type of the sockets' names.
**This type should be passed into every hook if you need to use multiple sockets.**
`Err` (default is `string`) - type of the socket error which is reachable by using hooks as` error` (not required).
`SReq` (default is `Req`) - type of serialized socket request which will be sent to the API (not required).
**This type should be returned from the `WebSocketOptions.serialize` function.**
`DRes` (default is `Res`) - type of deserialized socket response which is reachable by using hooks as `data` (not required).
**This type should be returned from the `WebSocketOptions.deserialize` function.**