mutation doesnt rollback query state on failure
The issue is that as soon as the applyOptimisticUpdate function is called to modify the localstore, the remoteQuerySet map within the RemoteQuerySet class is immediately updated to match the localstore values—this happens before the mutation is executed.
In the first screenshot, you can see that the backend still holds the unmodified value. In the second screenshot, however, the remoteQuerySet already reflects the updated value, even though the mutation hasn’t been executed yet.
Mutation would throw an exception on the backend and values are not rollbacked.
I did not find the reason why remoteQuerySet is set to localstore values before mutation is even executed.
16 Replies
hi @Starlord ! do you have a small repro of the behavior you're observing? I'd be curious what your optimistic update looks like, in particular.
one potential issue is that optimistic updates must not mutate the query values they observe (like
setState
in react) -- that might be causing this anomaly.can i share some screenshots? because cant share codebase
sure!
so once localstore setquery is called RemoteQuerySet is updated instantly to those values
the problem happens in mutationInternal between applyOptimisticUpdate and MutationRequest
ah, yeah it looks like
updateTaskCompletion
is mutating taskStatus
, which originates from localStore
instead, you can make a shallow copy of the object and then pass that to updateTaskStatus
its the same way like in docs no?
ah since
currentValue
is a number
it doesn't get mutated (currentValue + increment
creates a new primitive)
in this case, it should work if you change updateTaskCompletion
to
so it's creating a new JS object rather than updating the original taskStatus
object that lives within the remote query setah ok let me try
btw, one library I really like for working with this type of stuff is https://immerjs.github.io/immer/ -- it makes it look like you're just updating stuff directly but creates new objects under the hood as needed
Introduction to Immer | Immer
Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way.
makes it less annoying (both for convex optimistic updates but also react, redux, etc.)
oh you were right. its working now
amazing! sorry you ran into this, it's definitely a gotcha with these types of APIs in JS
thank you
I know some libraries have a dev mode where they freeze objects (so it'll throw an error if you try to mutate them), but there's a performance penalty to doing so
thank you for the help