I am trying to implement a messaging library Chatkit by Pusher in my React/Redux/redux saga app and I'm new to Redux. The code for connecting to chatkit looks like this:
const chatManager = new ChatManager({
instanceLocator: 'v1:us1:80215247-1df3-4956-8ba8-9744ffd12161',
userId: 'sarah',
tokenProvider: new TokenProvider({ url: 'your.auth.url' })
})
chatManager.connect()
.then(currentUser => {
console.log('Successful connection', currentUser)
})
.catch(err => {
console.log('Error on connection', err)
})
I need to store the chatManager and currentUser objects, (which are instances of complex classes with functions atttached) globally so that I can use them again later to join rooms, subscribe to events etc.
My first thought was that I should store it in Redux as that's now my "global store" but I then realised that it probably won't work as it won't be the original object I get back out of the store, it'll presumably a clone. I then read that apparently only plain objects are supposed to be stored in Redux.
So, where are things that aren't plain objects but do need to be stored globally? I don't want to put them on the window object as I may convert this to a React Native app and it seems messy anyway.
Per the Redux FAQ entry on storing "connection"-type objects:
Middleware are the right place for persistent connections like websockets in a Redux app, for several reasons:
- Middleware exist for the lifetime of the application
- Like with the store itself, you probably only need a single instance of a given connection that the whole app can use
- Middleware can see all dispatched actions and dispatch actions themselves. This means a middleware can take dispatched actions and turn those into messages sent over the websocket, and dispatch new actions when a message is received over the websocket.
- A websocket connection instance isn't serializable, so it doesn't belong in the store state itself​
edit
Here's my "sample socket middleware" example, updated to delay creating the socket until it sees a login action:
const createMySocketMiddleware = (url) => {
let socket;
return storeAPI => next => action => {
switch(action.type) {
case "LOGIN" : {
socket = createMyWebsocket(url);
socket.on("message", (message) => {
storeAPI.dispatch({
type : "SOCKET_MESSAGE_RECEIVED",
payload : message
});
});
break;
}
case "SEND_WEBSOCKET_MESSAGE": {
socket.send(action.payload);
return;
}
}
return next(action);
}
}