Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redux: synchronizing state among many users #18

Open
danburzo opened this issue Feb 13, 2017 · 7 comments
Open

Redux: synchronizing state among many users #18

danburzo opened this issue Feb 13, 2017 · 7 comments

Comments

@danburzo
Copy link

danburzo commented Feb 13, 2017

When building a React/Redux application that contains an amount state that is shared between many users, what is a good approach to synchronize the state so that when user A does action X, user B's state also updates to reflect the action, without having to refresh the app?

I'm thinking something along the lines of a Redux middleware that intercepts all actions and passes them over via Web Sockets to all the subscribed users. On the receiving end, we listen on the connection and dispatch the actions as they come -- I wonder if there's a library that deals specifically with this, and might have some extra subtlety implemented around dealing with 'conflicting' actions, etc.

@dariusbaba
Copy link

dariusbaba commented Feb 13, 2017

Web Sockets notifications? User A does action X, server notifies user B. User B requests latest data (not a full refresh). Just a thought.

@danburzo
Copy link
Author

@dariusbaba ah, yes; that might forego some of the complexity involved with merging actions -- instead of trying to patch the state on the receiving end, we just update a part of the state tree via API calls. Thanks for the idea! 🤔

(If I imagine things correctly, on the receiving end you'd need a function that maps incoming actions to the appropriate refresh action)

@dariusbaba
Copy link

dariusbaba commented Feb 13, 2017

We use an Immutable Js map as datastore and have a generic update function. Then we use the deepMerge method on the immutable map to update the store. For example:

store : {
collection1 :  new Map() ,
collection2:  new Map(),
}

Any backend call return data following the convention above. If we have new data on collection1 on the server, the call will return an object of the form:

{
collection1: Map(new data),
}

We have a generic update function that is called for all the incommig actions and refresh the datastore. So there is no need to map to appropriate refresh action.

@alexnm
Copy link

alexnm commented Feb 13, 2017

I played a little with RethinkDB and Horizon and I think it might be a great solution for your use because it's observable-based from the client to the database. However, it's still in its infancy and I wouldn't start a critical project with this setup today.

@tudorgergely
Copy link
Contributor

tudorgergely commented Feb 13, 2017

I would handle the updates on the backend and send via websockets to the frontend the updated data. Something along this lines:

  1. All users are connected via websockets and are ready to receive updates from server.
  2. User does action A
  3. Backend is updated and notifies via websockets other users which need the updated data.
  4. Receivers update their state by turning the data received from websockets into actions => updated state

I would not get into any implementation details (for now) but this is the main idea.

Firebase, horizon etc do this automatically, but there is not reason you cannot do it manually for a few actions (and not have to change your technology stack)

@danburzo
Copy link
Author

This short article describes how one might implement a Websocket communication layer between instances: https://medium.com/@Scarysize/syncing-redux-stores-across-browser-tabs-fff04f975423

I can imagine various ways of doing the communication:

Simple pipeline
The WebSocket acts as a simple transport layer for actions, relaying them over the wire:

Alice dispatches action -> Action gets serialized -> Action is transported via WS -> Action gets deserialized -> Bob dispatches action

(Of course, we'll want to make a distinction between local actions and remote actions, to avoid the Alice <-> Bob infinite ping-pong)

WS as action to refresh action transformer

Alice dispatches action -> Action gets serialized -> Back-end maps action to refresh action -> Refresh action gets deserialized -> Bob dispatches refresh action

This avoids the possible problem with infinite ping-pong, but bleeds implementation details (action definitions, and their relationships) to the back-end.

WS as action to updated data transformer

Same approach as above, but instead of returning refresh actions, it returns the updated (sub-)state that can then be merged into Bob's state directly.

(P.S. @alexnm thanks for the pointers, sounds interesting!)

@paulbrie
Copy link

I don't know if it fits your specific needs but firebase does a good job on this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants