Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redux-thunk with Websockets

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.

like image 217
Juliuszc Avatar asked Jun 28 '16 19:06

Juliuszc


3 Answers

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.

like image 152
markerikson Avatar answered Sep 30 '22 12:09

markerikson


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.

like image 21
Compulim Avatar answered Sep 30 '22 11:09

Compulim


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.

like image 32
mdworld Avatar answered Sep 30 '22 12:09

mdworld