Let us make up a toy case: Suppose we have an app that has a "thumb up" button for each post - you know, when clicking it, the button should become blue, and the server should store that this guy thumbs it up.
So my question is, what are the best practices to implement this? I have two naive solutions in my mind, but I think both of them have some disadvantages. So I wonder whether there is a better third solution, or one of mine is what everyone does.
For your information, here are my two attempts:
Method A: When clicking, trigger two things. (1) Directly modify the state (e.g. in Redux), setting state.thumbup=true
, and then React will automatically re-render the UI. At the same time, (2) send an HTTP post to the server. When the server receives it, it will update its database (e.g. user.setThumbUp(true);repo.save(user);
).
The problem is that, I have to duplicate my logic twice, once in the client ("if click, the state.thumbup
becomes 1"), and once in the server ("if client clicks, one location in the database changes to 1"). This is simple in our example, but it disobeys the KISS rule, and a lot of code duplicates when the action becomes complicated...
Method B: When clicking, the client does not modify any local state. Instead, we only send an HTTP post to the server. Then, the server receives it, and modifies its database. After we know the server has done its job, the client trigger an HTTP get, to fetch the latest state about the whole page. After the client gets the data, it renders and the user sees the thumb up being colored.
Of course, this makes the duplication of code disappear. However, now the user will wait for a long time (waiting the HTTP request) before he sees the UI is changed. It seems that this is also very bad...
Therefore, I wonder whether there is a better solution? Or is everyone simply using the first method? Thank you very much!
Method A is better. To address your concerns:
Duplication of logic: You'd only have to duplicate the "write operation" so to speak. The reducer would save the thumbs up state and the action creator would dispatch the api request to do "thumbs up" on the server. But the basic wiring of button -> thumbs up action remains the same. The React component doesn't know about optimistic updates and just renders its props. So it's not a duplication of logic per se, you're just adding more logic to improve the UX, which is legitimate.
Rollback/error handling: Method A and B can be combined. You would send off the api request for thumbs up, wait for it to succeeed or fail, and finally send a GET request that fetches the same resource you tried to change on the server (since its the source of truth). This rolls back the optimistic update, if the write operation failed. Or it simply does nothing if it succeeded, but guarantees that you have an up-to-date resource in your store.
However, I'd guess that 80% of React/Redux apps don't do optimistic updates since most developers test on fast internet connections and are simply not aware of bad UX with slow connections. But it's the right thing to do.