Keeping Client State Up-To-Date In Reagent / Clojurescript Keeping Client State Up-To-Date In Reagent / Clojurescript reactjs reactjs

Keeping Client State Up-To-Date In Reagent / Clojurescript


I agree with @myguidingstar that your problem is more about client-server synchronization than about clojure or reagent. You could have a similar problem, say, with GWT (been there, ...)

Should I make another call to the server (a GET request) after the initial POST is successful? This could replace the contents of the ratom. Then I'm making two requests.. which seems wasteful.

You seem to miss that POST requests can also trigger responses from the server.

The big question here is why do you need the DB state on the client? Do you have requirements which force you to minimize the amount of GET requests to fetch data from the server? Or do you have business logic implemented on the client (ClojureScript/reagent) side that just doesn't need server interaction? You need to consider also the other side of the same issue: Is it okay if your client state doesn't get updated in a while or could you run into consistency issues because "something else" is modifying the data on the server behind your client's back?

Finally, you say that you

.. don't know how I should synchronise it.

What exactly are your issues? Why not just update the app-state (swap! app-state update-in ...) after you've fetched the data from the server, as described in the reagent-tutorial?


This is a big question about client-server synchronization that most web apps struggle with.

There's a library by Tonsky for the very problem:

https://github.com/tonsky/datascript

Read his blog post and the example datascript-chat to understand the design.This will require a lot to learn, but I'm afraid it's the only way that is not kind of "doesn't feel right".


As others have noted, this is a common design challenge for any client/server application where there may be more than a single client. I think the key is in looking closely at what state you need to maintain in your client. Questions like "Does your client actually need up-to-date state information regarding the server or remote database or does it just need up-to-date information regarding the actions performed by the client? For example, do you need to know what is in a remote database table after an update or do you just need to know whether your update was successful or not?

The other thing I've seen which can lead devs down the wrong path is owrrying about efficiency too early. To gain efficiency, the design sometimes attempts to incorporate too much state in the local client, believing this will reduce the number of calls to the remote server and make the application more responsive. However, often you can end up with an overly complex implementation which is hard to get right with lots of local state management overhead, often including a lot of information which is only used/relevant in limited or infrequently used parts of the client interface. Next thing you know, your app is losing efficiency as it works to maintain state synchronisation which isn't needed.

The challenge here is due to our tendency to think about problems in a serialized manner. This is natural. However, the problem here doesn't quite fit with this way of thinking. The remote state of the system is changing at an unpredictable rate. Even if you adopt an architecture which pushes changes out to the client, you will run into problems related to working out how often such changes should be pushed out and then how to reflect those changes in the interface such that the user stil gets a consistent and meaningful picture.

My approach, which is just one of many and may not be the most ideal, is to model the web app along the same lines as many database clients (and to some extent even Clojure's own STM). The state in the client is a snapshot of the remote state at a particular point in time. It may not be accurate or up-to-date, but it should be consistent. When the client submits a change, it may or may not succeed, depending on what has changed in the server since I started to enter my change in the client. If it succeeds, it succeeds totally and if it fails, it fails totally.

As pointed out by others, this has no direct relationship to Reagent. This is a borader design issue. However, it may have an indirect impact. For example, when you update the reagent atom, your reagent contain er will be rendered. The atom is aware when it is updated, but it is not aware when the update is only a refresh of existing information with no change, so you really only want to update the atom when it needs updating because something has changed. However, unless this is happening really really frequently and your component is really really complicated, you probably won't see any real impact even if you do frequent refresh type updates anyway.

I would focus on keeping state to a minimum and developing a really simple design, then load test and work out if there are performance issues and deal with them as they arise.