-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
[Svelte 5] Runes ($effect, $derived) don't work as expected when values are nested inside an object. #9639
Comments
Pulling something out of a state object and then updating the same object again in an effect is going to cause issues. I would just not store the value redundantly in the first place: let note = $state({
contents: 'With Runes :(',
get lowercased() {
return this.contents.toLowerCase();
}
}); The class can also be simplified using class Note {
contents = $state() as string // <- fix for TS error
lowercased = $derived(this.contents.toLowerCase())
constructor(contents: string) {
this.contents = contents;
}
} Though the error is a bit of an annoyance in class fields. I deliberated whether I should suggest making the |
Not in a position to check this right now, but I'm pretty sure you can use a type argument to avoid the class Note {
contents = $state<string>();
lowercased = $derived(this.contents.toLowerCase());
constructor(contents: string) {
this.contents = contents;
}
} You can also do this, if you want the properties to be enumerable without adding a <script lang="ts">
let contents = $state('With Runes :)');
let note = $derived({
contents,
lowercased: contents.toLowerCase()
});
</script>
<input bind:value={contents} />
<pre>{JSON.stringify(note, null, 2)}</pre> The By using |
Just using the regular generic type arg does not work, as stated the type definition adds declare function $state<T>(initial: T): T;
declare function $state<T>(): T | undefined; |
Hmm. I think we should probably change that to this: declare function $state<T>(initial?: T): T; It might not be technically correct, but |
It's only really an issue with class fields. In other situations you usually have the initial value at hand already, for classes it first has to be passed in via the constructor. It is also still left to be seen how much classes will be used in the end. That is why I had not suggested that change already. |
Wouldn't mind the change much either, though. Just remembered that definite assignment assertions would work here, too: class Note {
contents = $state<string>()!;
...
} |
If this is solveable with |
We've been against Another solution - one we may need to add anyway because of how typescript may transpile this - is to allow people to initialize the variable with |
That doesn't seem to work, at least in the REPL |
Maybe a REPL issue, it worked locally and it appears to work in SvelteLab (try this template: https://www.sveltelab.dev/?t=five). |
Just to add to this issue: you still get <script>
let text = $state('initial');
let state = $state({});
$effect(() => { state.contents = text; })
</script>
text: <input bind:value={text} />
state.contents: <input bind:value={state.contents} /> |
prevents infinite loops when mutation happens inside an effect came up in #9639
* fix: handle ts expressions when dealing with runes related to #9639 * docs, more tests * simplify --------- Co-authored-by: Rich Harris <[email protected]>
I guess #9739 resolves this issue? No need of classes now! |
tracking down a bug with why something wasn't round tripped to storage due to a rune and the class missing toJson was pretty frustrating. |
@Rich-Harris really feels like the compiler could emit toJSON for any runes/props inside of a class. That would be a really good dx experience and work just like 4.x. |
Please don't comment on closed issues, especially with something that isn't directly related to the issue at hand. It's unlikely that the comment will be acted upon. There's a new issue button right there |
* Updated to svelte5 dep * added link resources * updated client hooks * Commented out legos * removed unused code * added temp tanstack svelte5 adaptor from pr * WIP rework data tables for svelte5 * Updated svelte * Temp impl for svelte persisted store https://twitter.com/puruvjdev/status/1787037268143689894/photo/1 joshnuss/svelte-persisted-store#251 * WIP Runes * More svelte 5 conversion * Updated package json * WIP Svelte 5 work * Upgraded typography components to runes and use new snippets and props * More runes work * More Svelte 5 work * Updated facet filters to runes * Upgraded to @exceptionless/fetchclient * Updated deps * Upgraded to latest fetch client * Updated shad * Upgrade to eslint 9 https://github.com/sveltejs/kit/pull/12268/files * fixed invalid ref * Converted slots * Updated deps * Added some snippets * WIP Dashboard * Updated tailwind * Fixed copy * Fixed slots * Updated deps * Updated data tables and summaries * More conversion * Updated deps * Converted all components to runes * Some dispatch changes * WIP: Dispatch Changes * Updated deps * more dispatch work * Fixed linting errors * Updated svelte * Updated shad * Updated typescript * Updated deps * Fixed fetch client * Fixed svelte errors. * added conditional icon check * Update deps * WIP: Use svelte-query-runes TanStack/query#6981 * WIP - Reworked snippets and some other fixes. * Updated deps * WIP - Svelte 5 work * Updated deps * Updated to latest tanstack table * WIP: Filter runes work. * Fixed more errors. * Updated deps * Use svelte query pkg * Updated svelte and vitest * Fixed svelte query issues, fixed linting issues, fixed eventing. * Fixed web socket events * Updated deps * Fixed some filtering issues * Fixed persisted store * Updated packages * Fixed filter reactivity * Updated deps * Updated deps * fixed svelte query issues * Use runed media query * Update deps * Use runed media query * Fixed svelte issue with state_unsafe_mutation sveltejs/svelte#12571 * Ensure all runes are serialized with toJSON sveltejs/svelte#9639 * Added document visibility store and fixed more upgrades * Updated deps * Updated queries * WIP: Demoting tabs * Updated deps * Updates to tab promotion * Fixed bind warnings * Updated deps * Use new svelte query apis * Updated deps * Fixed stack promotion * Fixed grid issues * Fixed fetch client issues with the login forms * Added custom auth serializer * Force package install due to svelte 5 peer deps * rebuilt lock file * Update Document Visibility helper to match new runed pattern
Describe the bug
When the state is an object, setting up reactive dependencies within the object is cumbersome / doesn't work as expected
Reproduction
Svelte-4 syntax - small, readable, and works as expected.
REPL
Svelte-5 syntax - doesn't work:
ERR_SVELTE_TOO_MANY_UPDATES
REPL
Since
$derived() can only be used as a variable declaration initializer or a class field
, the following doesn't work eitherThe solution recommended by @Rich-Harris is to use classes: https://www.youtube.com/watch?v=pTgIx-ucMsY&t=13986s
REPL
This kinda works, but
Type 'string | undefined' is not assignable to type 'string'
Note that explicitly typing the
$state()
rune by doingcontents: string = $state<string>()
doesn't help either - it gives the same typescript errorThe only way is to provide an initial value for the state, which seems wrong.
Logs
No response
System Info
Severity
annoyance
The text was updated successfully, but these errors were encountered: