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.
It's technically possible to do that, but you should not add class instances to the Redux state!. Both React and Redux expect that you're using plain JS objects, arrays, and primitives for your state - not class instances. They also expect that you update that data immutably.
Some users prefer to keep every single piece of data in Redux, to maintain a fully serializable and controlled version of their application at all times. Others prefer to keep non-critical or UI state, such as “is this dropdown currently open”, inside a component's internal state. Using local component state is fine.
The state in Redux is stored in memory, in the Redux store. This means that, if you refresh the page, that state gets wiped out. The state in redux is just a variable that persists in memory because it is referenced (via closure) by all redux functions. In redux, we know that the state is stored as an object.
Passing of state between Components using propsReact state should be stored in the most top-level component for which a subset of its sub-components will need access to the state.
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With