$: reactive shortcut is not current with multiple sync updates to a writeable store
See original GitHub issueDescribe the bug
$: does not reliably fire with a writeable store, while store.subscribe does.
It seems like all initial writeable store updates within the same tick are gathered, with only the last, most recent one firing for the $: reactive handler, usually. However, it seems like it can be possible for the $: handler to fire pre-maturely, when there are still other state updates to happen within the same tick, which wind up going un-reported.
See repro link below.
Reproduction
https://svelte.dev/repl/57dbee8266d840d09611daebee226b91?version=3.42.5
I get the following in the dev console. Note that the {loading: "true"}
update is not reported from the $: handler, with the XXX, until the NEXT update happens. This results in the wrong state being reported, initially.
Note that moving the call to sync up, fixes this. It seems like Svelte’s analysis of the code is missing an odd edge case.
https://svelte.dev/repl/e88c70d6fd224b0d84656f83afd7e63c?version=3.42.5
Logs
N/A
System Info
REPL
Severity
blocking an upgrade
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:110 (94 by maintainers)
To me this REPL still feels kind of backwards. I would’ve written it differently probably, avoiding the need for a rerun.
Still, I think having a possibility to opt in (not out) of reruns would be a good addition to the framework. We can’t expect people to write code like we want them to at all times, and when they realize they coded themselves into a situation where they need that rerun, it should be available.
Regarding syntax: I don’t like
$: { deps } { doStuff() }
. Reasons:prettier-plugin-svelte
” -> not true, it would be a huge undertaking to change this print.prettier-plugin-svelte
delegates formatting of script tags to the core Prettier formatters, so we either need to fork that (impossible to maintain), or inspect the resulting docs array (highly discouraged by the Prettier team, could break frequently if inner doc structure changes). The “Prettier prints it in a less connected way” also is a hint towards point 1.I actually really like @arxpoetica’s solution to make this a inner label, although I would maybe name it to make it more clear:
This would also make it possible to add more labels for more fine-tuned behavior later on. For example this could mean “these are my deps, but don’t rerun when one of them change while calculating this”:
Whereas
$rerunOn
means “rerun this block when any of the listed variables are invalidated, even if this block already ran”. There could be situations where you want both$deps
and$rerunOn
to be defined, and that would be possible now.Regardless of how this discussion turns out, we really should have an “advanced docs” section going into more details for things like this and for providing best practices.
I would add that I was curious how other frameworks would deal with this test case. First I tried Solid because it has a reputation for having one of the most, well, solid reactive systems (that self infers the dependencies like Svelte does). Seem to be behaving as expected with no surprises and very consistently. See here. It is not sensitive to the order of the effects and always logs 6 times.
React also resolves correctly although it has some sensitivity (number of operations) to the order of the effects. See here
How can we get svelte (which, generally speaking, has far superior DX relative to both of the above) to the same level of predictability and robustness?