Description
Describe the bug
I used a "getter", a$derived
and a $state
together inside a class.
This worked before, but after updating to the latest version it stopped being reliable.
I noticed that reactivity to the below mentioned get layout()
does not work reliably.
(it does start working in some conditions I could not understand)
→ TLDR: Using $derived
inside a class is unreliable, using a "getter" instead is not.
This version created a reactivity problem. Where even embedding the text {new Layout().layout}
would not be reactive to changes of #orientation
.
class Layout {
#orientation: OrientationType = $state("portrait-primary")
#orientationLock: OrientationType | null = $state(null)
#orientationEffective = $derived(this.#orientationLock ?? this.#orientation)
#isHorizontal = $derived(this.#orientationEffective.startsWith("landscape"))
// this private state is then exported using a getter
get layout(): LayoutType {
return this.#isLargeWidth
? "with-sidebar"
: this.#isHorizontal && PLATFORM === "mobile"
? "with-sidebar-tiny"
: "only-main"
}
}
→ This problem was solved when changing the $derived
variables into getters themselves:
// ...
get #orientationEffective() {
return this.#orientationLock ?? this.#orientation
}
get #isHorizontal() {
return this.#orientationEffective.startsWith("landscape")
}
// ...
Additional context: I use the resulting state inside a snippet and pass this snippet to another component to render it.
{#snippet snip()}
<PlayerTab
layout={LAYOUT.layout === "with-sidebar-tiny" ? "landscape" : "normal"}
/>
{/snippet}
Observing the state from the parent is NOT enough to fix the bug:
{LAYOUT.layout}
{#snippet snip()}
{LAYOUT.layout}
<PlayerTab
layout={LAYOUT.layout === "with-sidebar-tiny" ? "landscape" : "normal"}
/>
{/snippet}
HOWEVER observing it from inside <PlayerTab />
({LAYOUT.layout}
) IS ENOUGH to fix it.
Observing only the layout
prop (as text: {layout}
) is however not enough... How weird.
LAYOUT.layout
and layout
are both used in multiple {#if}
blocks/etc inside PlayerTab
.
Reproduction
I am very sorry to say that I was not able to reproduce this in the playground (tried for around 30 minutes)
→ However the described bug is 100% reliable, and also 100% fixable by changing $derived
s into "getter"s!
→ (It also seems to be related to the use of null ?? "fallback"
inside $derived
...?)
Logs
System Info
System:
OS: macOS 15.4.1
CPU: (20) x64 Intel(R) Xeon(R) W-2150B CPU @ 3.00GHz
Memory: 205.15 MB / 64.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 23.11.0 - /usr/local/bin/node
Yarn: 1.22.11 - /usr/local/bin/yarn
npm: 10.9.2 - /usr/local/bin/npm
pnpm: 10.7.1 - /usr/local/bin/pnpm
bun: 1.0.25 - /usr/local/bin/bun
Browsers:
Chrome: 136.0.7103.48
Safari: 18.4
npmPackages:
svelte: 5.28.2 => 5.28.2
Severity
blocking an upgrade