-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Assignments to $state()
break reactivity only out of scope. Breaks returning $state
of primitives
#13890
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
$state()
break reactivity if out of scope. Breaks returning $state
of primitives$state()
break reactivity only out of scope. Breaks returning $state
of primitives
I think you have a misunderstanding of how primitives work in JavaScript, because Svelte adheres to how JS works. In your first example: export function createClock () {
let clock = $state('')
$effect(() => {
clock = new Date().toLocaleString()
})
// The state will be set locallly
$inspect(clock)
// but it won't be returned as such
return clock
} Returning export function createClock () {
let clock = $state('')
$effect(() => {
clock = new Date().toLocaleString()
})
$inspect(clock)
return () => clock
} Objects work differently, in that unlike primitives, they're passed by reference in JavaScript. That's why the reactivity remains within them, either via |
Hello, You cannot return a state from a function, because this will be replaced by his value at this moment. Maybe one day we will have an API for this (see this comment : #9237 (comment) ) PS : note that you can use an effect to start/clean the interval $effect(() => {
let interval = window.setInterval(() => {
clock.timeString = new Date().toLocaleString()
}, 500);
return () => clearInterval(interval);
}); |
@trueadm Thanks for chiming in. I am indeed aware of the differences between primitives and objects, and that primitives can only be assigned, thus my comparison table including both assignments and mutations. I was, however mistaken:
since I was under the impression that it should return the return {
clock: $.get(clock), Now, how can we access the proxy object? We can definitely read it when calling
Your quoted solution doesn't seem to work: REPL clock: () => $.get(clock), Is there a way to get the reactive state proxy, so that it can be used in the parent? |
It does work, you just didn't call the function. If you have an object proxy, then returning it will always return the reference, as the value is the reference. |
@trueadm wow sorry, I need to close my laptop and have some sleep, my eyes are no longer working. Thank you for the help! |
Uh oh!
There was an error while loading. Please reload this page.
Describe the bug
For runes to be a competent
$store
alternative/replacement, we need to be able to create$state
inside a method, optionally react to it with any$effect/$derived
and then return that proxified$state
to a caller.When creating a
$state
, then assigning it in a callback (either inside the callback of an$effect
, an interval or other method) and returning it from the function, reactivity is lost, so any changes to that$state
won't propagate out of scope. However, the$state
is still reactive within the scope that it was defined in. REPL - minimal with$effect
or REPL - with createIntervalThis effectively means that we cannot return the
$state
of a primitive, and the current behavior of$state
locally and amongst functions or.svelte.js
files seems inconsistent.However, if we return the
$state({})
of an object, we can see that, even though both assignments and mutations trigger reactivity within scope, only mutations get across the function scope. Working Object Mutation REPLWhat's most strange is that assignments to a
$state
do in fact propagate signals, but they can only be received in the scope the$state
was defined in.Can be worked around by wrapping the return value in an object and ensuring we only assign. Causes confusion when porting from
Svelte 4
to5
, since we used to only assign and destructure to trigger reactivityobj = {...obj, value:1 }
, and specifically that doesn't work.Reproduction
Here's a Large REPL table with all 9 combinations:
$state
, function-returned$state
, function-returned$state
from a.svelte.js
fileprimitive
, returnobject
and set inside fn, returnObject
and mutate inside fnObject.assign
And buttons to set the state externally, which behave exactly like the closures do.
What's less expected is that if we're assigning locally to that returned
$state
(columns 1, 2).svelte.js
file, the assignment will overwrite the $state, making it diverge from what's inside the function scope. This probably warrants a second issue, once this is fixed.Please note that wrapping the function return in a
$state
would be pointless, since in that case, the function'srunes
/listeners won't receive the event.Logs
No response
System Info
svelte.dev playground, `[email protected]`
Severity
blocking an upgrade
The text was updated successfully, but these errors were encountered: