Skip to content

Uptimistic Updates

Adam Hooper edited this page Nov 5, 2020 · 1 revision

The problem: when the client sends an update (like "Add report block"), that user wants to see the outcome right away -- before the server responds.

But it can't know whether the update will succeed or not -- or whether other users' updates will come first.

Part A of the solution: The client stores state.optimisticUpdates, an ordered sequence of deltas it expects the server to send. The client adds an optimistic update when it sends a request. If the request fails, it deletes the optimistic update.

Then there's a race: if the request succeeds, the optimistic update may already have applied, and it may only arrive later. So the client can't modify state.optimisticUpdates when the request succeeds.

Part B of the solution: The client sends an optimisticUpdateId along with any request that it will store in state.optimisticUpdates. The server sends an update.optimisticId along with any Update that is produced as a result of that request.

Here are all the places where this cross-cutting concern applies:

  • Redux: state.optimisticUpdates modifies the rest of the state. When rendering, select the optimistically-updated state.
  • Client-side API calls: pass a guaranteed-unique-across-all-clients optimisticUpdateId when adding an optimistic update to the Redux state.
  • Client-side API-call failure: remove the optimistic update from state.optimisticUpdates
  • Client-side receive APPLY_DELTA: remove the optimistic update from state.optimisticUpdates
  • Server-side API calls: accept a optimisticUpdateId argument
  • Server-side commands.do(): accept a optimistic_update_id and attach it to the delta sent to all clients upon success