React Hook for WebSocket communication
Installations
npm install react-use-websocket
Developer Guide
Typescript
Yes
Module System
CommonJS
Node Version
20.12.1
NPM Version
10.5.0
Score
99.6
Supply Chain
100
Quality
90.5
Maintenance
100
Vulnerability
100
License
Releases
Contributors
Languages
TypeScript (100%)
Developer
robtaussig
Download Statistics
Total Downloads
18,075,071
Last Day
36,992
Last Week
164,996
Last Month
748,924
Last Year
8,715,589
GitHub Statistics
1,687 Stars
283 Commits
140 Forks
7 Watching
16 Branches
27 Contributors
Package Meta Information
Latest Version
4.13.0
Package Id
react-use-websocket@4.13.0
Unpacked Size
195.74 kB
Size
40.95 kB
File Count
78
NPM Version
10.5.0
Node Version
20.12.1
Publised On
04 Feb 2025
Total Downloads
Cumulative downloads
Total Downloads
18,075,071
Last day
-10.1%
36,992
Compared to previous day
Last week
-20%
164,996
Compared to previous week
Last month
3.2%
748,924
Compared to previous month
Last year
65.8%
8,715,589
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dev Dependencies
21
React useWebSocket
Note: wss://demos.kaazing.com/echo
has been down lately, so the demo will fail to connect when using that as the endpoint. On the plus side, this demonstrates the behavior of a connection failure.
React Hook designed to provide robust WebSocket integrations to your React Components. Experimental support for SocketIO (read documentation below for more information)
Pull requests welcomed!
New in 4.0.0
react-use-websocket
now supports (and depends on) React 18. If you are not ready to upgrade to React 18, please install version3.0.0
:
npm install --save react-use-websocket@3.0.0
//or
yarn add react-use-websocket@3.0.0
New in 2.0.0
useWebSocket
now returns an object instead of an array. This allows you to pick out specific features/properties to suit your use-case as well as removing mental overhead of keeping track of item order.lastJsonMessage
andsendJsonMessage
added to return value to reduce need to stringify and parse outgoing and incoming messages at the component level.- The optional object passed as the second parameter no longer needs to be static.
- Components can close/unsubscribe from a WebSocket by passing
false
as the third parameter. This provides a more explicit solution than the previous method of setting thesocketUrl
tonull
. Both methods work and are supported usage.
Example Implementation
1import React, { useState, useCallback, useEffect } from 'react'; 2import useWebSocket, { ReadyState } from 'react-use-websocket'; 3 4export const WebSocketDemo = () => { 5 //Public API that will echo messages sent to it back to the client 6 const [socketUrl, setSocketUrl] = useState('wss://echo.websocket.org'); 7 const [messageHistory, setMessageHistory] = 8 useState < MessageEvent < any > [] > []; 9 10 const { sendMessage, lastMessage, readyState } = useWebSocket(socketUrl); 11 12 useEffect(() => { 13 if (lastMessage !== null) { 14 setMessageHistory((prev) => prev.concat(lastMessage)); 15 } 16 }, [lastMessage]); 17 18 const handleClickChangeSocketUrl = useCallback( 19 () => setSocketUrl('wss://demos.kaazing.com/echo'), 20 [] 21 ); 22 23 const handleClickSendMessage = useCallback(() => sendMessage('Hello'), []); 24 25 const connectionStatus = { 26 [ReadyState.CONNECTING]: 'Connecting', 27 [ReadyState.OPEN]: 'Open', 28 [ReadyState.CLOSING]: 'Closing', 29 [ReadyState.CLOSED]: 'Closed', 30 [ReadyState.UNINSTANTIATED]: 'Uninstantiated', 31 }[readyState]; 32 33 return ( 34 <div> 35 <button onClick={handleClickChangeSocketUrl}> 36 Click Me to change Socket Url 37 </button> 38 <button 39 onClick={handleClickSendMessage} 40 disabled={readyState !== ReadyState.OPEN} 41 > 42 Click Me to send 'Hello' 43 </button> 44 <span>The WebSocket is currently {connectionStatus}</span> 45 {lastMessage ? <span>Last message: {lastMessage.data}</span> : null} 46 <ul> 47 {messageHistory.map((message, idx) => ( 48 <span key={idx}>{message ? message.data : null}</span> 49 ))} 50 </ul> 51 </div> 52 ); 53};
From the example above, the component will rerender every time the readyState
of the WebSocket changes, as well as when the WebSocket receives a message (which will change lastMessage
). sendMessage
is a memoized callback that will pass the message to the current WebSocket (referenced to internally with useRef
).
A demo of this can be found here. Each component uses its own useWebSocket
hook. This implementation takes advantage of passing an optional options object (documented below). Among setting event callbacks (for onmessage
, onclose
, onerror
, and onopen
) that will log to the console, it is using the share
option -- if multiple components pass the same socketUrl to useWebSocket
and with share
set to true, then only a single WebSocket will be created and useWebSocket
will manage subscriptions/unsubscriptions internally. useWebSocket
will keep track of how many subscribers any given WebSocket has and will automatically free it from memory once there are no subscribers remaining (a subscriber unsubscribes when it either unmounts or changes its socketUrl). Of course, multiple WebSockets can be created with the same target url, and so components are not required to share the same communication pipeline.
Features
- Handles reconnect logic
- Multiple components can (optionally) use a single WebSocket, which is closed and cleaned up when all subscribed components have unsubscribed/unmounted
- Written in TypeScript
- Socket.io support
- Heartbeat support
- No more waiting for the WebSocket to open before messages can be sent. Pre-connection messages are queued up and sent on connection
- Provides direct access to unshared WebSockets, while proxying shared WebSockets. Proxied WebSockets provide subscribers controlled access to the underlying (shared) WebSocket, without allowing unsafe behavior
- Seamlessly works with server-sent-events and the EventSource API
Getting Started
1npm install react-use-websocket
1import useWebSocket from 'react-use-websocket'; 2 3// In functional React component 4 5// This can also be an async getter function. See notes below on Async Urls. 6const socketUrl = 'wss://echo.websocket.org'; 7 8const { 9 sendMessage, 10 sendJsonMessage, 11 lastMessage, 12 lastJsonMessage, 13 readyState, 14 getWebSocket, 15} = useWebSocket(socketUrl, { 16 onOpen: () => console.log('opened'), 17 //Will attempt to reconnect on all close events, such as server shutting down 18 shouldReconnect: (closeEvent) => true, 19});
Interface
1type UseWebSocket<T = unknown> = ( 2 //Url can be return value of a memoized async function. 3 url: string | () => Promise<string>, 4 options: { 5 fromSocketIO?: boolean; 6 queryParams?: { [field: string]: any }; 7 protocols?: string | string[]; 8 share?: boolean; 9 onOpen?: (event: WebSocketEventMap['open']) => void; 10 onClose?: (event: WebSocketEventMap['close']) => void; 11 onMessage?: (event: WebSocketEventMap['message']) => void; 12 onError?: (event: WebSocketEventMap['error']) => void; 13 onReconnectStop?: (numAttempts: number) => void; 14 shouldReconnect?: (event: WebSocketEventMap['close']) => boolean; 15 reconnectInterval?: number | ((lastAttemptNumber: number) => number); 16 reconnectAttempts?: number; 17 filter?: (message: WebSocketEventMap['message']) => boolean; 18 disableJson?: boolean; 19 retryOnError?: boolean; 20 eventSourceOptions?: EventSourceInit; 21 heartbeat?: boolean | { 22 message?: "ping" | "pong" | string | (() => string); 23 returnMessage?: "ping" | "pong" | string; 24 timeout?: number; 25 interval?: number; 26 }; 27 } = {}, 28 shouldConnect: boolean = true, 29): { 30 sendMessage: (message: string, keep: boolean = true) => void, 31 //jsonMessage must be JSON-parsable 32 sendJsonMessage: (jsonMessage: T, keep: boolean = true) => void, 33 //null before first received message 34 lastMessage: WebSocketEventMap['message'] | null, 35 //null before first received message. If message.data is not JSON parsable, then this will be a static empty object 36 lastJsonMessage: T | null, 37 // -1 if uninstantiated, otherwise follows WebSocket readyState mapping: 0: 'Connecting', 1 'OPEN', 2: 'CLOSING', 3: 'CLOSED' 38 readyState: number, 39 // If using a shared websocket, return value will be a proxy-wrapped websocket, with certain properties/methods protected 40 getWebSocket: () => (WebSocketLike | null), 41}
Requirements
- React 16.8+
- Cannot be used within a class component (must be a functional component that supports React Hooks)
Async Urls
Instead of passing a string as the first argument to useWebSocket, you can pass a function that returns a string (or a promise that resolves to a string). It's important to note, however, that other rules still apply -- namely, that if the function reference changes, then it will be called again, potentially instantiating a new WebSocket if the returned url changes.
1import useWebSocket from 'react-use-websocket'; 2 3// In functional React component 4const getSocketUrl = useCallback(() => { 5 return new Promise((resolve) => { 6 setTimeout(() => { 7 resolve('wss://echo.websocket.org'); 8 }, 2000); 9 }); 10}, []); 11 12const { sendMessage, lastMessage, readyState, getWebSocket } = useWebSocket( 13 getSocketUrl, 14 STATIC_OPTIONS 15);
If getSocketUrl
throws an error and Options#retryOnError
is true
, then getSocketUrl
will be called at an interval consistent with the retry behavior defined by Options#reconnectAttempts
and Options#reconnectInterval
.
API
sendMessage
1type sendMessage = (message: string, keep: boolean = true) => void;
The argument sent through sendMessage will be passed directly to WebSocket#send
. sendMessage
will be static, and thus can be passed down through children components without triggering prop changes. Messages sent before the WebSocket is open will be queued up and sent on connection. If you don't want to use messages queue for a particular message you should use a 'keep' parameter.
sendJsonMessage
1type sendJsonMessage = (message: any, keep: boolean = true) => void;
Message will first be passed through JSON.stringify
.
lastMessage
1type lastMessage = WebSocketEventMap['message'];
Will be an unparsed MessageEvent
received from the WebSocket.
lastJsonMessage
1type lastJsonMessage = any;
A JSON.parse
d object from the lastMessage
. If lastMessage
is not a valid JSON string, lastJsonMessage
will be an empty object. If Options#disableJson
is true
, lastMessage
will not be automatically parsed, and lastJsonMessage
will always be null
.
readyState
1enum ReadyState { 2 UNINSTANTIATED = -1, 3 CONNECTING = 0, 4 OPEN = 1, 5 CLOSING = 2, 6 CLOSED = 3, 7}
Will be an integer representing the readyState
of the WebSocket. -1
is not a valid WebSocket readyState
, but instead indicates that the WebSocket has not been instantiated yet (either because the url is null
or connect param is false
)
getWebSocket
1type getWebSocket = () => WebSocketLike | Proxy<WebSocketLike>;
If the WebSocket is shared, calling this function will lazily instantiate a Proxy
instance that wraps the underlying WebSocket. You can get and set properties on the return value that will directly interact with the WebSocket, however certain properties/methods are protected (cannot invoke close
or send
, and cannot redefine any of the event handlers like onmessage
, onclose
, onopen
and onerror
. An example of using this:
1const { sendMessage, lastMessage, readyState, getWebSocket } = useWebSocket( 2 'wss://echo.websocket.org', 3 { share: true } 4); 5 6useEffect(() => { 7 console.log(getWebSocket().binaryType); 8 //=> 'blob' 9 10 //Change binaryType property of WebSocket 11 getWebSocket().binaryType = 'arraybuffer'; 12 13 console.log(getWebSocket().binaryType); 14 //=> 'arraybuffer' 15 16 //Attempt to change event handler 17 getWebSocket().onmessage = console.log; 18 //=> A warning is logged to console: 'The WebSocket's event handlers should be defined through the options object passed into useWebSocket.' 19 20 //Attempt to change an immutable property 21 getWebSocket().url = 'www.google.com'; 22 console.log(getWebSocket().url); 23 //=> 'wss://echo.websocket.org' 24 25 //Attempt to call webSocket#send 26 getWebSocket().send('Hello from WebSocket'); 27 //=> No message is sent, and no error thrown (a no-op function was returned), but an error will be logged to console: 'Calling methods directly on the WebSocket is not supported at this moment. You must use the methods returned by useWebSocket.' 28}, []);
If the WebSocket is not shared (via options), then the return value is the underlying WebSocket, and thus methods such as close
and send
can be accessed and used.
Reconnecting
By default, useWebSocket
will not attempt to reconnect to a WebSocket. This behavior can be modified through a few options. To attempt to reconnect on error events, set Options#retryOnError
to true
. Because CloseEvent
s are less straight forward (e.g., was it triggered intentionally by the client or by something unexpected by the server restarting?), Options#shouldReconnect
must be provided as a callback, with the socket CloseEvent
as the first and only argument, and a return value of either true
or false
. If true
, useWebSocket
will attempt to reconnect up to a specified number of attempts (with a default of 20
) at a specified interval (with a default of 5000
(ms)). The option properties for attempts is Options#reconnectAttempts
and the interval is Options#reconnectInterval
. As an example:
1const didUnmount = useRef(false); 2 3const [sendMessage, lastMessage, readyState] = useWebSocket( 4 'wss://echo.websocket.org', 5 { 6 shouldReconnect: (closeEvent) => { 7 /* 8 useWebSocket will handle unmounting for you, but this is an example of a 9 case in which you would not want it to automatically reconnect 10 */ 11 return didUnmount.current === false; 12 }, 13 reconnectAttempts: 10, 14 reconnectInterval: 3000, 15 } 16); 17 18useEffect(() => { 19 return () => { 20 didUnmount.current = true; 21 }; 22}, []);
Alternatively, you can provide a function for Options#reconnectInterval
that accepts as a parameter the nth last attempt and returns a number, which represents how long the next interval should be. This should enable a higher degree of control if you wish to employ more advanced reconnect strategies (such as Exponential Backoff):
1const [sendMessage, lastMessage, readyState] = useWebSocket(
2 'wss://echo.websocket.org',
3 {
4 shouldReconnect: (closeEvent) => true,
5 reconnectAttempts: 10,
6 //attemptNumber will be 0 the first time it attempts to reconnect, so this equation results in a reconnect pattern of 1 second, 2 seconds, 4 seconds, 8 seconds, and then caps at 10 seconds until the maximum number of attempts is reached
7 reconnectInterval: (attemptNumber) =>
8 Math.min(Math.pow(2, attemptNumber) * 1000, 10000),
9 }
10);
Options
1interface Options { 2 share?: boolean; 3 shouldReconnect?: (event: WebSocketEventMap['close']) => boolean; 4 reconnectInterval?: number | ((lastAttemptNumber: number) => number); 5 reconnectAttempts?: number; 6 filter?: (message: WebSocketEventMap['message']) => boolean; 7 disableJson?: boolean; 8 retryOnError?: boolean; 9 onOpen?: (event: WebSocketEventMap['open']) => void; 10 onClose?: (event: WebSocketEventMap['close']) => void; 11 onMessage?: (event: WebSocketEventMap['message']) => void; 12 onError?: (event: WebSocketEventMap['error']) => void; 13 onReconnectStop?: (numAttempted: number) => void; 14 fromSocketIO?: boolean; 15 queryParams?: { 16 [key: string]: string | number; 17 }; 18 protocols?: string | string[]; 19 eventSourceOptions?: EventSourceInit; 20 heartbeat?: 21 | boolean 22 | { 23 message?: 'ping' | 'pong' | string; 24 returnMessage?: 'ping' | 'pong' | string; 25 timeout?: number; 26 interval?: number; 27 }; 28}
shouldReconnect
See section on Reconnecting.
reconnectInterval
Number of milliseconds to wait until it attempts to reconnect. Default is 5000. Can also be defined as a function that takes the last attemptCount and returns the amount of time for the next interval. See Reconnecting for an example of this being used.
Event Handlers: Callback
Each of Options#onMessage
, Options#onError
, Options#onClose
, and Options#onOpen
will be called on the corresponding WebSocket event, if provided. Each will be passed the same event provided from the WebSocket.
onReconnectStop
If provided in options, will be called when websocket exceeds reconnect limit, either as provided in the options or the default value of 20.
share: Boolean
If set to true
, a new WebSocket will not be instantiated if one for the same url has already been created for another component. Once all subscribing components have either unmounted or changed their target socket url, shared WebSockets will be closed and cleaned up. No other APIs should be affected by this.
fromSocketIO: Boolean
SocketIO acts as a layer on top of the WebSocket protocol, and the required client-side implementation involves a few peculiarities. If you have a SocketIO back-end, or are converting a client-side application that uses the socketIO library, setting this to true
might be enough to allow useWebSocket
to work interchangeably. This is an experimental option as the SocketIO library might change its API at any time. This was tested with Socket IO 2.1.1
.
queryParams: Object
Pass an object representing an arbitrary number of query parameters, which will be converted into stringified query params and appended to the WebSocket url.
1const queryParams = { 2 user_id: 1, 3 room_id: 5, 4}; 5//<url>?user_id=1&room_id=5
useSocketIO
SocketIO sends messages in a format that isn't JSON-parsable. One example is:
"42["Action",{"key":"value"}]"
An extension of this hook is available by importing useSocketIO
:
1import { useSocketIO } from 'react-use-websocket'; 2 3//Same API in component 4const { sendMessage, lastMessage, readyState } = useSocketIO( 5 'http://localhost:3000/' 6);
It is important to note that lastMessage
will not be a MessageEvent
, but instead an object with two keys: type
and payload
.
heartbeat
If the heartbeat
option is set to true
or has additional options, the library will send a 'ping' message to the server every interval
milliseconds. If no response is received within timeout
milliseconds, indicating a potential connection issue, the library will close the connection. You can customize the 'ping' message by changing the message
property in the heartbeat
object. If a returnMessage
is defined, it will be ignored so that it won't be set as the lastMessage
.
1const { sendMessage, lastMessage, readyState } = useWebSocket(
2 'ws://localhost:3000',
3 {
4 heartbeat: {
5 message: 'ping',
6 returnMessage: 'pong',
7 timeout: 60000, // 1 minute, if no response is received, the connection will be closed
8 interval: 25000, // every 25 seconds, a ping message will be sent
9 },
10 }
11);
filter: Callback
If a function is provided with the key filter
, incoming messages will be passed through the function, and only if it returns true
will the hook pass along the lastMessage
and update your component.
Example:
1 filter: (message) => { 2 // validate your message data 3 if (isPingMessage(message.data)) { 4 // do stuff or simply return false 5 updateHeartbeat() 6 return false 7 } else { 8 return true 9 } 10 },
The component will rerender every time the WebSocket receives a message that does not match your conditional in this case isPingMessage
, if the condition is true, you can do some stuff, for this example that is updating the heartbeat time, but you could just avoid unnecessary renders simply returning false
.
disableJson: Boolean
If true
, lastMessage
will not be automatically parsed and returned as lastJsonMessage
, in which case lastJsonMessage
will always be null
.
useEventSource
1import { useEventSource } from 'react-use-websocket'; 2 3//Only the following three properties are provided 4const { lastEvent, getEventSource, readyState } = useEventSource( 5 'http://localhost:3000/', 6 { 7 withCredentials: true, 8 events: { 9 message: (messageEvent) => { 10 console.log('This has type "message": ', messageEvent); 11 }, 12 update: (messageEvent) => { 13 console.log('This has type "update": ', messageEvent); 14 }, 15 }, 16 } 17);
If used, an EventSource will be instantiated instead of a WebSocket. Although it shares a very similar API with a WebSocket, there are a few differences:
- There is no onclose event, nor is there an event for readyState changes -- as such, this library can only 'track' the first two readyStates: CONNECTING (0) and OPEN (1). The
EventSource
will close when your component unmounts. - Currently, the library will set the readyState to CLOSED on the underlying
EventSource
's onerror callback, and will also triggerOptions#onClose
, if provided. In this case, reconnect logic is driven byOptions#retryOnError
, instead ofOptions#shouldReconnect
. - There is no 'CLOSING' readyState for
EventSource
, and as such, the CLOSED readyState is2
for anEventSource
, whereas it is3
for a WebSocket. For purposes of internal consistency, thereadyState
returned byuseWebSocket
will follow theWebSocket
enumeration and use3
for the CLOSED event for both instance types. getEventSource
will return the underlying EventSource, even ifOptions#share
is used -- as opposed to theWebSocket
equivalent which returns aProxy
.- There is no concept of sending messages from the client, and as such
sendMessage
will not be provided.
Reset Global State
There are some cases when the global state of the library won't reset with the page. The main behavior relies on the fact that a single page application operates only in one window, but some scenarios allow us to make a new window via window.open
and inject code there. In that case, child window will be closed, but the global state of the library remains the same in the main window. This happens because react does not finish components lifecycle on window close.
To avoid troubles with the new initialization of components related to the same URL, you can reset the global state for a specific connection based on your own logic.
1import React, { useEffect } from 'react'; 2import { resetGlobalState } from 'react-use-websocket'; 3 4// insside second window opened via window.open 5export const ChildWindow = () => { 6 useEffect(() => { 7 window.addEventListener('unload', () => { 8 resetGlobalState('wss://echo.websocket.org'); 9 }); 10 }, []); 11};
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: MIT License: LICENSE:0
Reason
7 commit(s) and 4 issue activity found in the last 90 days -- score normalized to 9
Reason
5 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
- Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3
- Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7
Reason
Found 10/22 approved changesets -- score normalized to 4
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 18 are checked with a SAST tool
Score
4.7
/10
Last Scanned on 2025-01-27
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn MoreOther packages similar to react-use-websocket
react-native-use-websocket
React Native Hook designed to provide robust WebSocket integrations to your Components.
react-use-websockets
React hook to facilitate connections to a WebSocket server running a specific protocol. Normal Javascript WebSockets created via `new WebSocket(url)` allow the sending and receiving of raw data packets. This WebSockets client works on top of that and assu
@jawis/use-websocket
React hook to open/close a websocket connection when a component mounts/unmounts
@alexhayton/react-native-use-websocket
React Native Hook designed to provide robust WebSocket integrations to your Components.