$: reactive statement ignored during beforeUpdate
Describe the bug
$: reactive statements are ignored if values are modified in beforeUpdate.
Reproduction
Solve https://learn.svelte.dev/tutorial/update and add
$: {
console.log("autoscroll", autoscroll)
}
You'll see that nothing will be logged. If you add some variable changes like
let st = true
$: {
console.log("autoscroll", autoscroll)
st = !st
}
you'll see they don't change
Logs
No response
System Info
https://learn.svelte.dev/tutorial/update on Chrome
Severity
Pretty serious bug
@ibmua I've been able to recreate what you've described in learn.svelte.dev, but after creating this repro repl, I don't think this is a Svelte issue. Could be something about the web containers setup (I'm not really sure). Let me know if the repro accurately reproduces the scenario you've outlined
I'm not sure I fully understand what the issue here is, but I'm intrigued by this part of the code.
$: {
console.log({val1, val2, domDep}),
val2 = !val2
}
If we are updating the value of val2 inside this reactive block, and the block is supposed to run each time val2 changes because we are logging it to the console. Wouldn't this cause (shouldn't this cause) an infinite loop?
No, it doesn't. When a variable changes (marked dirty), the following happens:
- looping over each
$:block and running the ones that depend on dirtied variables; - running
beforeUpdate; - marking all variables as up to date;
- updating DOM;
- running
afterUpdate.
Step 3 prevents infinite loops, plus proper udirting variables individually is too tricky or probably even impossible.
Svelte 5 will change the behavior here using the new Runes API. Using $effect and $effect.pre you can listen to the variables you're interested in and it will always refire when they changed.
Note that the REPL in the second post would result in an infinite loop right now because it's writing and reading the same value, triggering the effect over and over again. We may look into fixing more obvious cases of this / warn against it so that doesn't happen as easily.
I thought about infinite loops cause by self-triggering $effect and came to idea that if your logic cause infinite loops then the logic is wrong and it needs some loop guard or its improvement.
But maybe it would nice to be able to disable $effects' self-triggering though a flag in the second param. Though it may not solve infinite loops over multiple $effects.
Closing since this will be addressed in Svelte 5 as pointed out in https://github.com/sveltejs/svelte/issues/8750#issuecomment-1812370086