Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to store Class instance for reusability in Redux?

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.

like image 781
jonhobbs Avatar asked Aug 13 '18 23:08

jonhobbs


People also ask

Can I store class instances in Redux?

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.

Should I keep all component's state in Redux store?

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.

Where does Redux actually store data?

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.

What state should I store in Redux?

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.


1 Answers

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);
    }
}
like image 140
markerikson Avatar answered Nov 02 '22 15:11

markerikson