query icon indicating copy to clipboard operation
query copied to clipboard

Angular query: Optimistic updates are not synchronous

Open stevesan opened this issue 4 months ago • 6 comments

Describe the bug

Here's a stackblitz that repro's the issue about 20% of the time (I think it's timing related): https://stackblitz.com/edit/stackblitz-starters-hn17w1mv?file=src%2Fmain.ts,src%2Findex.html

If you click "edit" and change the "whatever" to just "1", then tab out to trigger blur, you'll see the "whatever" show up for 1 frame. I think this is happening because the optimistic update (which should set the title to "1") is not happening until the next frame. So when I set the "isEditingTitle" signal to false, it flickers the old title for 1 frame. I would expect the optimistic update to be immediate and synchronous, like how normal signals behave, so this flicker never happens.

Generally speaking, this can happen whenever you have a UX that let's the user preview an edit before committing it. In this case, the preview is the input text box, and commiting it is blurring. It would be even more noticeable if the input field looked exactly like the non-editing text.

What are people's thoughts on this? Is this not a use case many encounter?

Your minimal, reproducible example

https://stackblitz.com/edit/stackblitz-starters-hn17w1mv?file=src%2Fmain.ts,src%2Findex.htmlhttps://stackblitz.com/edit/stackblitz-starters-hn17w1mv?file=src%2Fmain.ts,src%2Findex.html

Steps to reproduce

  1. Click the "edit" button
  2. Change "whatever" to just "w"
  3. Press Tab to trigger blur and finish editing.

Expected behavior

20% of the time, you'll see "whatever" show up for 1 frame. Desired behavior: I would expect the optimistic update to immediately take effect, and the text immediately shows "w".

How often does this bug happen?

Sometimes

Screenshots or Videos

No response

Platform

  • OS: macOS
  • Browser: Google Chrome, Version 141.0.7390.54 (Official Build) (arm64)

Tanstack Query adapter

angular-query

TanStack Query version

^5.69.1

TypeScript version

^5.6.3

Additional context

No response

stevesan avatar Oct 06 '25 19:10 stevesan

i have a workaround that's OK-ish: read the signal, but ignore the value - instead, get the latest value from the cache directly, so use getQueryData. reading the signal is still good, so your update code is subscribed to it. but when other signals trigger an update, like isEditingTitle, reading the cache will get the optimistically updated value correctly.

the worst part of this solution, however, is you now have to be careful about the order of your signal sets: your mutation must come first, then your other signals. not great. (UPDATE: actually the ordering may not matter, due to how Angular runs effects. it doesn't immediately run an effect when you update a signal, it'll just queue it up, so you should get the updated cache value always.)

stevesan avatar Oct 06 '25 23:10 stevesan

thanks for chiming in, @wook95 ! can you clarify which version that code is from? it's surprising that moving that line would fix it, cuz it doesn't look like anything async is happening in the body at all. unless you removed some of that stuff?

stevesan avatar Oct 10 '25 14:10 stevesan

Sorry, I need to retract my previous comment - I made a mistake in my analysis.

I can confirm @stevesan 's workaround works well. The downside is having to manually add all related signals as dependencies.

Another option is setTimeout(() => this.isEditing.set(false), 0) which works without the computed wrapper, but feels a bit hacky.

Would be great if this could be handled at the library level, similar to React Query's useSyncExternalStore.

wook95 avatar Oct 11 '25 13:10 wook95

makes sense, @wook95 . i think another solution, which i have yet to try, is to use "queueMicrotask" for notification scheduling: https://tanstack.com/query/latest/docs/reference/notifyManager#notifymanagersetscheduler. i will try this and report back!

stevesan avatar Oct 13 '25 17:10 stevesan

ok, i think setScheduler works! here it is: https://stackblitz.com/edit/stackblitz-starters-cwxlsq6x?file=src%2Fmain.ts

now the question is, are there any reasons to NOT do this? it's an example in the docs, with no warnings, so hopefully it's fine to do?

stevesan avatar Oct 13 '25 17:10 stevesan

if people aren't aware of any issues with this fix, then perhaps the only action item here is to update the docs? i'm happy to update the angular query docs, although it seems this fix is not angular-specific.

stevesan avatar Oct 15 '25 01:10 stevesan