5

I want to create a websocket on demand when certain components want to subscribe to data. How can I share the websocket instance in a redux fashion?

action.js

export function subscribeToWS(url) {
   return dispatch => {
      let websocket = new WebSocket(url)
      websocket.on('connect', () => {
         websocket.send("subscribe") 
      }
      websocket.on('message', (message) => {
        dispatch(storeNewData(message))
      }
   } 
}

I could do something like this, but this would require a new instance for every new subscription.

Juliuszc
  • 337
  • 1
  • 3
  • 14

3 Answers3

4

The standard place to put things like persistent connection objects is inside middleware. And, in fact, there's literally dozens of existing middlewares that demonstrate that approach, with most of them listed over at https://github.com/markerikson/redux-ecosystem-links/blob/master/middleware.md#sockets-and-adapters . You should be able to use some of those as-is, or at least as examples.

markerikson
  • 42,022
  • 7
  • 87
  • 109
  • 11
    I have the same question as the OP -- thanks for the link above. I looked there and found this: https://github.com/luskhq/redux-ws, but that project is deprecated in favor of `redux thunk`. I've used thunk before with http async requests, but I'm wondering if there are examples for websockets. I'm having trouble finding any. – matthewatabet Feb 24 '17 at 13:37
  • 4
    I have similar issues as @matthewatabet. I am looking for examples how to exec actions properly on new messages from WebSocket. I guess that it is easy, but a simple example would be extremely helpful. – abguy Jul 25 '17 at 11:49
  • @matthewatabet here is an approach https://stackoverflow.com/questions/37876889/react-redux-and-websockets-with-socket-io and this is the tutorial i followed, not sure if the best approach , I am doing this for the first time, so... https://dev.to/aduranil/how-to-use-websockets-with-redux-a-step-by-step-guide-to-writing-understanding-connecting-socket-middleware-to-your-project-km3 – user3808307 Apr 26 '20 at 21:46
2

You can look at redux-websocket-bridge. It unfold Web Socket messages into Redux action, and relay Redux action to Web Socket.

Upside of this approach: you can use Redux on your server as API endpoint, replacing standard REST API with less code.

Also, if your server do not send Flux Standard Action, you can still use redux-websocket-bridge for raw messages. It works with string, ArrayBuffer, and Blob. Of course, you can always write a small middleware to translate them into Flux Standard Action, e.g. messages from Slack RTM API.

Compulim
  • 1,118
  • 9
  • 18
  • I was searching for such redux's socket library for so many days. I tried using "redux-socket.io" with "socket.io-client" to connect to my spring boot app, but no success. Your answer has solved all my problems. I was stuck for so many days. Thank you very much – ashish pandey May 15 '20 at 22:07
1

Although this is quite an old question by now, it popped up several times when looking for an example. As @matthewatabet and @abguy mention, https://github.com/luskhq/redux-ws just mentions it has been deprecated and you can use Redux Thunk, without an example specific for web sockets.

For future reference, I found this article that outlines an example, that is implemented in a Github repo, starting on this file. This is for socket.io, but using web sockets directly should be similar.

Summarizing, in the Component call dispatch with addNewItemSocket:

<RaisedButton
    label="Click to add!" primary={true}
    onTouchTap={ () => {
        const newItem = ReactDOM.findDOMNode(this.refs.newTodo.input).value
        newItem === "" ?  alert("Item shouldn't be blank")
                       :  dispatch(addNewItemSocket(socket,items.size,newItem)) 
                        {/*: dispatch(addNewItem(items.size,newItem))*/}
        ReactDOM.findDOMNode(this.refs.newTodo.input).value = ""
      }
    }
/>

In the actions file, declare addNewItemSocket as:

export const addNewItemSocket = (socket,id,item) => {
    return (dispatch) => {
        let postData = {
                id:id+1,
                item:item,
                completed:false
             }
        socket.emit('addItem',postData)     
    }   
}

To handle incoming messages from the socket, in the constructor of the component:

socket.on('itemAdded',(res)=>{
   console.dir(res)
   dispatch(AddItem(res))
})

And in the actoins file, declare AddItem as:

export const AddItem = (data) => ({
    type: "ADD_ITEM",
    item: data.item,
    itemId:data.id,
    completed:data.completed
})

For me this is still new, so any feedback is appreciated. I will also file a PR with https://github.com/luskhq/redux-ws to have an example listed there.

mdworld
  • 48
  • 7