Svelte Reactivity Bug with `$derived` in class · Issue #15853 · sveltejs/svelte · GitHub | Latest TMZ Celebrity News & Gossip | Watch TMZ Live
Skip to content

Svelte Reactivity Bug with $derived in class #15853

Closed
@timephy

Description

@timephy

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 $deriveds 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    p0stuff we should fix ASAP

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      TMZ Celebrity News – Breaking Stories, Videos & Gossip

      Looking for the latest TMZ celebrity news? You've come to the right place. From shocking Hollywood scandals to exclusive videos, TMZ delivers it all in real time.

      Whether it’s a red carpet slip-up, a viral paparazzi moment, or a legal drama involving your favorite stars, TMZ news is always first to break the story. Stay in the loop with daily updates, insider tips, and jaw-dropping photos.

      🎥 Watch TMZ Live

      TMZ Live brings you daily celebrity news and interviews straight from the TMZ newsroom. Don’t miss a beat—watch now and see what’s trending in Hollywood.