Skip to content

WebSocket

The WebSocket task handler allows to create a WebSocket connection, send messages, and listen on incoming ones.

Configuration

Parameter Type Description
socketFactory (connectionUrl: string) => WebSocketLike Optional. Function that will be used to create the socket, useful to provide compatibility layers (e.g. Primus, SockJS) or enhanced versions of WebSocket. Defaults to creating a standard WebSocket
encode (data: any) => any Optional. Function to encode data from a send task into a wire format. Defaults to JSON.stringify
decode (data: any) => any Optional. Function to decode data from the wire into a format useful for application code. Defaults to JSON.parse

Example:

import ReconnectingWebSocket from 'reconnecting-websocket'
import { configureAgents, createSocketAgent } from 'redux-agent'

store.subscribe(configureAgents([
  createSocketAgent({ 
    // Provide enhanced/wrapped implementation
    socketFactory: (url) => new ReconnectingWebSocket(url)
    // skip JSON encoding
    encode: (data) => data,
    // skip JSON decoding
    decode: (data) => data 
  })
], store))

Task: Listen

This task describes a connection intent, the actions that will to notify about connection status, and the action that will notify of incoming messages.

{
  type: 'socket',
  op: 'listen',
  url: string,          // socket endpoint URL, e.g. wss://example.com/
  actions: {
    connect: string,    // action type to dispatch when the socket connects
    disconnect: string, // action type to dispatch when the socket disconnects
    error: string,      // action type to dispatch when an error occurs
    message: string,    // action type to dispatch when a message is received
  }
}

Tip

To disconnect a socket, simply remove the task (see how in the example).

Actions

Event Type Meta Payload
connect None None
disconnect None None
error None None
message None Received message

Task: Send

{
  type: 'socket',
  op: 'send',
  data: any,      // data to send, will be encoded to JSON
  actions: {
    sent: string // action type to dispatch when the message has been sent
  }
}

Warning

The sent action can be a dummy (it doesn’t need to be handled by any reducer) but needs to be dispatched, and thus specified, because it will signal to the task reducer that the send task can be removed from the store. This requirement will be lifted in future versions.

Actions

Name Meta Payload
sent None Note

Example

Run this example »

import {
  addTask, delTasks, reduceReducers, taskReducer
} from 'redux-agent'

const MAX_EVENTS = 4

const reducer = (state, action) => {
  switch (action.type) {
    case 'CONNECT_WEB_SOCKET':
      return addTask(state, {
        type: 'socket',
        op: 'listen',
        url: 'wss://ws-beta.kraken.com/',
        actions: {
          connect: 'SOCKET_CONNECTED',
          disconnect: 'SOCKET_DISCONNECTED',
          error: 'SOCKET_ERROR',
          message: 'SOCKET_MESSAGE_RECEIVED'
        }
      })

    case 'SUBSCRIBE_TO_CURRENCY_INFO':
      return addTask(state, {
        type: 'socket',
        op: 'send',
        data: {
          event: 'subscribe',
          pair: ['XBT/USD', 'XBT/EUR'],
          subscription: { name: 'ticker' }
        },
        actions: {
          sent: 'SOCKET_MESSAGE_SENT'
        }
      })

    case 'DISCONNECT_WEB_SOCKET':
      return delTasks(state,
        (t) => t.type === 'socket')

    case 'SOCKET_MESSAGE_RECEIVED':
      const { events } = state.liveCurrencyUpdates
      return {
        ...state,
        liveCurrencyUpdates: {
          ...state.liveCurrencyUpdates,
          events: events.length < MAX_EVENTS
            ? events.concat(action.payload)
            : events.slice(0, -1).concat(action.payload)
        }
      }

    default:
      return state
  }
}

export default reduceReducers(reducer, taskReducer)