useWebSocket

Connect to a WebSocket and re-render with its status and latest message.

function useWebSocket<In = unknown, Out = unknown>(
  url: string | null | undefined,
  options?: UseWebSocketOptions<In, Out>
): UseWebSocketResult<In, Out>;

function useWebSocket<In, Out>(
  client: WebSocketClient<In, Out> | null | undefined,
  options?: WebSocketHandlers<In>
): UseWebSocketResult<In, Out>;

Usage

With a URL

import { useWebSocket } from 'react-websocket';

function Prices() {
  const { status, lastMessage } = useWebSocket<{ price: number }>('wss://api.example.com/prices', {
    json: true
  });
  return <p>{status === 'open' ? lastMessage?.price : status}</p>;
}

Every component that passes the same URL (and the same protocols) shares one connection. The first component to mount with a URL creates it, and its connection options are used for everyone. A render React throws away doesn't count. Options passed by later components for the same URL are ignored, except handlers and enabled, which are per component. In development, a later component that passes different connection options logs a warning naming them. If two components need different options for the same URL, create separate clients with createWebSocket.

Changing url closes the old connection (once nothing else uses it) and opens the new one.

With a client

import { createWebSocket, useWebSocket } from 'react-websocket';

const chat = createWebSocket<ChatIn, ChatOut>('wss://api.example.com/chat', { json: true });

function Composer() {
  const { status, send } = useWebSocket(chat, {
    onMessage: message => console.log(message)
  });
  // …
}

Connection options come from createWebSocket. Only handlers and enabled are accepted here.

Disconnected

Pass null or undefined to stay disconnected. The status is 'idle', and send returns false without queueing.

useWebSocket(roomId ? `wss://api.example.com/rooms/${roomId}` : null);

Parameters

ParameterType
url / clientstring | WebSocketClient | null | undefinedWhat to connect to
optionsUseWebSocketOptions / WebSocketHandlersSee below

Options

With a URL, options accepts every connection option plus the handlers below.

Handlers

OptionType
onOpen(event: Event) => voidThe socket opened, initially or after a reconnect
onMessage(message: In, event: MessageEvent) => voidA message arrived and passed parse/json and schema
onClose(close: CloseInfo) => voidA socket closed, whether or not it will be retried
onError(error: Event | Error) => voidA socket error, a MessageError, or an error from the constructor or url function
enabledbooleanfalse releases this component's hold and stops its handlers. Default true

Handlers always see the latest props and state, and changing them never reconnects. You don't need useCallback, useEffectEvent or the React Compiler for that.

Handlers belong to the component: they run only while it is mounted and enabled. Every component sharing a connection receives every event.

Returns

UseWebSocketResult<In, Out>:

FieldType
statusStatus'idle', 'connecting', 'open', 'reconnecting' or 'closed'
lastMessageIn | undefinedThe most recent message, kept across reconnects
attemptnumberConsecutive failed attempts since the last stable connection (one that stayed open for reconnect.minUptime). 0 while open
send(message: Out, options?: SendOptions) => booleanSends now, or queues until open (see SendOptions). Returns true if sent immediately
close(code?: number, reason?: string) => voidCloses and stops reconnecting, for every component sharing the connection
reconnect() => voidDrops the socket and connects again immediately
clientWebSocketClient<In, Out> | nullThe underlying client, or null when disconnected

send, close and reconnect keep the same identity across renders, so they are safe in dependency arrays and as props to memoized children.

Behavior

  • Renders. The component re-renders when the status changes and on every message. For high-frequency streams, use useWebSocketEvent and useWebSocketStatus, which don't re-render per message. See Performance.
  • Lifecycle. The connection opens on mount (in an Effect) and closes one tick after the last component using it unmounts. StrictMode and <Activity> don't create duplicate sockets. See StrictMode, Activity and lifecycle.
  • Server rendering. Renders status: 'idle' and never connects. See Server rendering.
  • After close(). The status stays 'closed' while components remain mounted. Call reconnect() to start again. Once every component unmounts, the next mount connects normally, as it does after a close() while none was mounted.

Caveats

  • useWebSocket(url) with the same URL but different json, schema or reconnect options in two components uses the first component's options for both, and warns in development. Use createWebSocket instead.
  • lastMessage is for "show the latest value" UIs. Don't collect messages by watching it in an Effect: if several messages arrive before React renders, you only see the last one. Use onMessage instead, which runs once per message.