Description
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
<script>
let note = {contents: 'Without Runes :)', lowercased: ''};
$: note.lowercased = note.contents.toLowerCase();
</script>
<input bind:value={note.contents} />
<pre>{JSON.stringify(note, null, 2)}</pre>
Svelte-5 syntax - doesn't work: ERR_SVELTE_TOO_MANY_UPDATES
REPL
<script>
let note = $state({contents: 'With Runes :(', lowercased: ''});
$effect(() => { note.lowercased = note.contents.toLowerCase(); })
</script>
<input bind:value={note.contents} />
<pre>{JSON.stringify(note, null, 2)}</pre>
Since $derived() can only be used as a variable declaration initializer or a class field
, the following doesn't work either
<script>
let note = $state({contents: 'With Runes :(', lowercased: ''});
note.lowercased = $derived(note.contents)
</script>
<input bind:value={note.contents} />
<pre>{JSON.stringify(note, null, 2)}</pre>
The solution recommended by @Rich-Harris is to use classes: https://www.youtube.com/watch?v=pTgIx-ucMsY&t=13986s
REPL
<script lang="ts">
class Note {
contents: string = $state()
lowercased: string = $state()
constructor(contents: string) {
this.contents = contents;
this.lowercased = contents.toLowerCase();
}
toJson() {
return {
contents: this.contents,
lowercased: this.lowercased
}
}
}
let note = new Note('With Runes :(');
$effect(() => { note.lowercased = note.contents.toLowerCase(); })
</script>
<input bind:value={note.contents} />
<pre>{JSON.stringify(note.toJson(), null, 2)}</pre>
This kinda works, but
- gives a typescript error
Type 'string | undefined' is not assignable to type 'string'
- is much more code for object creation and serialization
Note that explicitly typing the $state()
rune by doing contents: string = $state<string>()
doesn't help either - it gives the same typescript error
The only way is to provide an initial value for the state, which seems wrong.
Logs
No response
System Info
N/A
Severity
annoyance