Skip to content

toStore runs outside component lifecycle #15426

@mcous

Description

@mcous

Describe the bug

Overview

As we've been migrating our app over to Svelte 5, we've been leaning on calling toStore to convert props and other reactive state over to stores in order to pass them on to internal and external libraries that are not yet on Svelte 5. We always call toStore inside a component.

  1. We have a component that uses toStore on a prop rendered inside {#each} and {#if} blocks
  2. The loop/condition data changes, causing a component to unmount
  3. We hit Prop value can be different than guaranted by TypeScript #14725, and the prop becomes undefined
  4. The toStore getter is called with an undefined value from the prop
  5. If the prop is expected to be an object, then we get unhandled TypeError: Cannot read properties of undefined errors

I think this issue is related to, but distinct from, #14725. When a component is destroyed, I think any toStore call inside that component should be unhooked just like a $derived or $effect would be unhooked.

Workaround

We've defined our own implementation of toStore that avoids these issues (but can only be used in components):

const toStore = <T>(get: () => T): Readable<T> => {
  const store = writable(get())
  $effect.pre(() => {
    store.set(value());
  });
  return store;
}

Conjecture

After taking a look at the implementation of toStore, I wonder if the code should check effect_tracking() before creating a new effect_root I misunderstood how effect_tracking works, it doesn't look like this would do anything for the problem

Reproduction

To reproduce the kind of issue we're hitting, click the "Clear data" button in playground example below. You will see an unhandled exception in the console

https://svelte.dev/playground/a5f2d0f6c31842a299fe8e1b154c9b44?version=5.21.0

TypeError: Cannot read properties of undefined (reading 'value')
    at eval (playground:output:3207:51)
    at eval (playground:output:3176:20)
    at update_reaction (playground:output:1799:57)
    at update_effect (playground:output:1955:19)
    at process_effects (playground:output:2154:8)
    at flush_queued_root_effects (playground:output:2043:30)

System Info

System:
    OS: macOS 14.2.1
    CPU: (8) arm64 Apple M2
    Memory: 83.25 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.18.1 - ~/.nvs/default/bin/node
    npm: 10.8.2 - ~/.nvs/default/bin/npm
    pnpm: 8.15.6 - ~/.nvs/default/bin/pnpm
    bun: 1.1.34 - /opt/homebrew/bin/bun
  Browsers:
    Safari: 17.2.1
  npmPackages:
    svelte: 5.20.0 => 5.20.0

Severity

annoyance

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions