react-use-websocket

repository·master·Indexed 23 days ago

https://github.com/robtaussig/react-use-websocket

A React Hook for robust, production-ready WebSocket communication. Features include automatic reconnection with exponential backoff, Socket.io support, heartbeat (ping/pong) configuration, and the ability to share a single WebSocket connection across multiple components. It provides utilities for sending raw or JSON messages, monitoring connection readyState, and filtering incoming messages.

Tokens
5K
Snippets
7
Records
29
Agent score
84%

What's inside react-use-websocket

  1. Use useWebSocket with shared connections

    master

    If multiple components pass the same socketUrl to useWebSocket and the share option is set to true, only a single WebSocket will be created. The hook manages subscriptions/unsubscriptions internally. The WebSocket is automatically cleaned up from memory once all subscribers have unmounted or changed their socketUrl.

    When sharing, getWebSocket() returns a proxy-wrapped WebSocket that provides controlled access to the underlying shared connection without allowing unsafe behavior.

  2. How to use Async URLs with useWebSocket

    master

    Instead of a static string, you can pass a function that returns a string or a Promise that resolves to a string as the first argument to useWebSocket.

    Important: If the function reference changes, the hook will be called again, which may instantiate a new WebSocket if the returned URL is different. Use useCallback to maintain a stable function reference.

    import React, { useCallback } from 'react';
    import useWebSocket from 'react-use-websocket';
    
    // In functional React component
    const getSocketUrl = useCallback(() => {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve('wss://echo.websocket.org');
        }, 2000);
      });
    }, []);
    
    const { sendMessage, lastMessage, readyState, getWebSocket } = useWebSocket(
      getSocketUrl,
      STATIC_OPTIONS
    );
  3. Configure automatic reconnection

    master

    By default, useWebSocket does not reconnect. To enable reconnection, configure the following options:

    1. retryOnError: Set to true to attempt reconnection on error events.
    2. shouldReconnect: A callback function (event: CloseEvent) => boolean. If it returns true, the hook attempts to reconnect.
    3. reconnectAttempts: The maximum number of reconnection attempts (default is 20).
    4. reconnectInterval: The delay between attempts. This can be a number (ms) or a function (attemptNumber: number) => number for advanced strategies like Exponential Backoff.

    Exponential Backoff Example:

    const [sendMessage] = useWebSocket('wss://echo.websocket.org', {
      shouldReconnect: () => true,
      reconnectAttempts: 10,
      reconnectInterval: (attemptNumber) => Math.min(Math.pow(2, attemptNumber) * 1000, 10000),
    });
  4. Basic usage of useWebSocket

    master

    The useWebSocket hook provides a robust way to integrate WebSockets into functional React components. It returns an object containing several properties to manage the connection and messages.

    Key features include:

    • Automatic reconnection logic.
    • Support for Socket.io.
    • Message queuing (messages sent before the connection is open are queued and sent once connected).
    • Heartbeat support.
    • Ability to share a single WebSocket connection across multiple components using the share: true option.
    import useWebSocket from 'react-use-websocket';
    
    // In a functional React component
    const socketUrl = 'wss://echo.websocket.org';
    
    const {
      sendMessage,
      sendJsonMessage,
      lastMessage,
      lastJsonMessage,
      readyState,
      getWebSocket,
    } = useWebSocket(socketUrl, {
      onOpen: () => console.log('opened'),
      // Will attempt to reconnect on all close events, such as server shutting down
      shouldReconnect: (closeEvent) => true,
    });
  5. Configure Heartbeat (Ping/Pong)

    master

    To prevent connection timeouts, you can enable a heartbeat. If heartbeat is enabled, the library sends a 'ping' message at a specified interval. If no response is received within the timeout period, the connection is closed.

    Heartbeat Configuration Object:

    • message: The string to send as a ping (e.g., 'ping').
    • returnMessage: The expected response (e.g., 'pong'). If defined, this response is ignored and will not be set as lastMessage.
    • timeout: Time in ms to wait for a response before closing the connection.
    • interval: Time in ms between pings.

    Example:

    const { sendMessage } = useWebSocket('ws://localhost:3000', {
      heartbeat: {
        message: 'ping',
        returnMessage: 'pong',
        timeout: 60000,
        interval: 25000,
      },
    });
  6. Configure WebSocket Options

    master

    The useWebSocket hook accepts an Options object to customize behavior:

    OptionTypeDescription
    sharebooleanIf true, multiple components using the same URL will share a single WebSocket instance.
    shouldReconnect(event) => booleanCallback to determine if the socket should reconnect on close.
    reconnectIntervalnumber | functionDelay between reconnect attempts. Function receives attemptNumber.
    reconnectAttemptsnumberMax number of reconnection attempts.
    filter(message) => booleanFunction to filter incoming messages. Only messages returning true trigger a component re-render.
    disableJsonbooleanIf true, lastJsonMessage will always be null.
    retryOnErrorbooleanIf true, attempts reconnection on error events.
    onOpen(event) => voidCallback triggered on the open event.
    onClose(event) => voidCallback triggered on the close event.
    onMessage(event) => voidCallback triggered on the message event.
    onError(event) => voidCallback triggered on the error event.
    onReconnectStop(numAttempted) => voidCallback triggered when the reconnection limit is reached.
    fromSocketIObooleanExperimental: enables compatibility with SocketIO backends.
    queryParamsRecord<string, string | number>Object of query parameters to append to the URL.
    protocolsstring | string[]Sub-protocol string or array of strings.
    heartbeatboolean | objectEnables heartbeat pings. See 'Heartbeat' section for object schema.
  7. Monitor connection status with readyState

    master

    The readyState property returns an integer representing the current state of the WebSocket connection.

    ReadyState Enum Values:

    • -1 (UNINSTANTIATED): The WebSocket has not been instantiated yet (e.g., url is null or connect param is false).
    • 0 (CONNECTING): The connection is being established.
    • 1 (OPEN): The connection is active.
    • 2 (CLOSING): The connection is in the process of closing.
    • 3 (CLOSED): The connection is closed.
  8. Reset global state with resetGlobalState

    master

    In Single Page Applications (SPAs), if you open new windows via window.open, the global state of the library might persist in the main window even after the child window is closed, because React does not finish the component lifecycle on window close.

    To prevent issues when re-initializing components with the same URL, you can manually reset the global state for a specific connection using resetGlobalState(url).

    import React, { useEffect } from 'react';
    import { resetGlobalState } from 'react-use-websocket';
    
    // inside second window opened via window.open
    export const ChildWindow = () => {
      useEffect(() => {
        window.addEventListener('unload', () => {
          resetGlobalState('wss://echo.websocket.org');
        });
      }, []);
    };
  9. Access the underlying WebSocket with getWebSocket

    master

    The getWebSocket function returns the underlying WebSocket instance (or a Proxy if share: true is used).

    When share: true is enabled:

    • The returned value is a Proxy that wraps the WebSocket.
    • You can read and set properties like binaryType (e.g., getWebSocket().binaryType = 'arraybuffer').
    • Restrictions: You cannot invoke close() or send() directly on the proxy, and you cannot redefine event handlers (onmessage, onclose, etc.) or immutable properties like url. You must use the methods returned by the hook instead.

    When share: false (default):

    • The function returns the actual underlying WebSocket, allowing direct access to close() and send().
    const { sendMessage, lastMessage, readyState, getWebSocket } = useWebSocket(
      'wss://echo.websocket.org',
      { share: true }
    );
    
    useEffect(() => {
      // Change binaryType property
      getWebSocket().binaryType = 'arraybuffer';
    
      // Note: getWebSocket().send('...') will log a warning and do nothing if shared
    }, []);
  10. Use useSocketIO for SocketIO backends

    master

    If you are connecting to a SocketIO backend, use the useSocketIO hook. SocketIO uses a non-standard message format that is not directly JSON-parsable by standard WebSocket clients.

    Key Differences:

    • lastMessage is not a MessageEvent; it is an object with { type, payload }.
    • The API is identical to useWebSocket.
    import { useSocketIO } from 'react-use-websocket';
    
    const { sendMessage, lastMessage, readyState } = useSocketIO(
      'http://localhost:3000/'
    );
  11. Use the useEventSource hook

    master

    The useEventSource hook allows you to use the browser's EventSource API (Server-Sent Events) instead of WebSockets. It provides a similar API to useWebSocket but with specific differences:

    • Events: You define event handlers within the events option object (e.g., message, update).
    • Ready States: It only tracks CONNECTING (0) and OPEN (1). For internal consistency, the returned readyState will use 3 for CLOSED (matching the WebSocket enumeration).
    • Error Handling: If an onerror callback occurs, the readyState is set to CLOSED and Options#onClose is triggered. Reconnection is driven by Options#retryOnError rather than Options#shouldReconnect.
    • No Outbound Messages: Since EventSource is a unidirectional protocol, sendMessage and sendJsonMessage are not provided.
    • Instance Access: getEventSource returns the underlying EventSource instance directly, even if Options#share is enabled.
    import { useEventSource } from 'react-use-websocket';
    
    //Only the following three properties are provided
    const { lastEvent, getEventSource, readyState } = useEventSource(
      'http://localhost:3000/',
      {
        withCredentials: true,
        events: {
          message: (messageEvent) => {
            console.log('This has type "message": ', messageEvent);
          },
          update: (messageEvent) => {
            console.log('This has type "update": ', messageEvent);
          },
        },
      }
    );