-2

The premise

The issue at hand is a multifaceted one. What is the course that's being followed in a real production environment, what's considered a better solution in terms of safety vs production cost, etc.
I'm currently developing a React web app utilizing Redux for storing the state tree of the app. At the same time, I'm creating a RESTful API with Spring Boot to serve as a back-end server to which the React app can rely for various operations. I'm storing the user data (be it authentication, metadata and application specific data) in Firestore accessible only by the Spring backend (for security reasons). When a user correctly logins in the React App, a GET request is dispatched to fetch their data from Firestore.

The dilemma

Now, when a user alters their data while logged in I'm faced with the following dilemma.

  • Either update the local state, in Redux in particular, and then dispatch a POST request to update the data stored in Firestore,
  • Or, straight up dispatch the POST request from the get-go and then dispatch another GET request to fetch the updated state.

Pros and cons

  • The first approach seems to be the better in terms of user experience as the user would have immediate visual feedback that his action was completed (say he wanted to delete a post from a list of posts, the post is immediately removed). The local storage is responsible for the rendering of the app so no matter the wait for the POST request to complete, the user will be correctly up to date. Of course, this isn't all good as modifying local storage when the actual data in the database are not yet updated isn't at all safe or really synchronous.

  • The second approach, it introduces a possibly strenuous operation that might (or might not) take a long time to conclude. BUT the state will always be correct, or at least as long as the Firestore database has a non-corrupted representation.

So, with all that said, what is your opinion on a correct approach that would satisfy both user experience and safety. (Please keep in mind, the local storage is NEVER looked up as a basis of synchronization with the database. If the local storage gets tampered with or corrupted, the changes will never reach the database.)

Invalid_Path
  • 321
  • 3
  • 8

1 Answers1

1

When you're using a client-side Firestore SDK, the two approaches are actually implemented in the same way.

You'd call the API to update the document, which then immediately fires events for any local listeners you have, even before sending the update to the servers. When it gets a response from the server (which may be much later in case the device is offline), the client either updates the metadata of the local cache to reflect the status, or (if the write failed/was rejected) reverts the local data to the correct state.

In your UI you can either just show the data that is fired to the local events (which is what most apps do), or you can reflect the metadata too. The latter takes the form of two flags in the DocumentSnapshot.metadata. From there:

  • hasPendingWrites: True if the snapshot contains the result of local writes (e.g. set() or update() calls) that have not yet been committed to the backend
  • fromCache: True if the snapshot was created from cached data rather than guaranteed up-to-date server data.

Check the documentation link for full details.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Through your answer and the documentation you linked I understood that the term I was searching was "latency compensation". I'm going to implement the way you propose by reflecting changes on a local scale first and if an error occurs on the server side, then revert back those changes. – Invalid_Path Sep 04 '20 at 10:49