sveltejs / svelte

web development for the rest of us
https://svelte.dev
MIT License
79.92k stars 4.25k forks source link

Possible regression? Reactivity on store members triggers infinite loop in svelte 5 (works in svelte 4) #14306

Open fnimick opened 5 hours ago

fnimick commented 5 hours ago

Describe the bug

When using a store for reactivity, where the store contains an object, svelte 4 allows a reactive block to set a store member based on the value of another store member, without triggering reactivity on the whole store.

In svelte 5, this appears to no longer be possible - assignments to $store.foo trigger reactivity on $store.bar.

Example: the svelte 4 version runs once, the svelte 5 version triggers an infinite loop, when the button is clicked.

<script>
    import { writable } from 'svelte/store';
    let s = writable({foo: 'foo', bar: null});

    $: {
        if ($s.foo === 'baz') {
            $s.bar = 'some';
        } else {
            $s.bar = null;
        }
    }

    // $effect(() => {
    //  if ($s.foo === 'baz') {
    //      $s.bar = 'some';
    //  } else {
    //      $s.bar = null;
    //  }
    // })
</script>

<p>{JSON.stringify($s)}</p>
<button onclick={() => {$s.foo = ($s.foo === 'baz' ? 'foo' : 'baz')}}>modify</button>

I'm not sure how to work around this when dealing with libraries that use stores - I am not in control here, and need to update the value of one store member when another store member changes.

Reproduction

https://svelte.dev/playground/hello-world?version=5.2.0#H4sIAAAAAAAAE32QT0-EMBDFv8qkIQESQu8IGG_Ggx48Wg_8mZrG0pJ21nUl_e6mC6jRjadp5v2m780szHQTsordotYWjtbpETIcFeGYs4JJpdGz6mlhdJojFxus2Kdu5rn0b6gp9vrO46X-YA2hIc8qVvvBqZlaYQSpabaOYIGjU9T1GiGAdHaCdJ3knqzD9CqyGgk8NF9otkhrK0iltWkBfecqMAetQx5pIyipYIlVkJKQJb6U1kLTNJD23Uea76KgxJd956CB1NtpMxMUALXHC1Q02ZlYwmrHOSQoJQ6UZTk07TrJOfzrf9YvRzhLP1P8Zr-CrOT2CrkwNf--sanndrl7fLgvPTllXpQ8ZYnPQ83nVpi6PxBZA9YMWg2vzbJl3-P-DQ7X68mh2hYJoZ3sqOSp5utnLSsY4TuxitwBw3P4BNax-WxhAgAA

Logs

No response

System Info

System:
    OS: macOS 15.1
    CPU: (10) arm64 Apple M1 Pro
    Memory: 128.16 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.13.1 - ~/.asdf/installs/nodejs/20.13.1/bin/node
    Yarn: 1.22.19 - ~/.yarn/bin/yarn
    npm: 10.5.2 - ~/.asdf/plugins/nodejs/shims/npm
    pnpm: 9.7.0 - ~/.asdf/shims/pnpm
  Browsers:
    Chrome: 130.0.6723.117
    Safari: 18.1
  npmPackages:
    svelte: ^5.0.0 => 5.2.0

Severity

blocking an upgrade

fnimick commented 5 hours ago

Proposed solution from the discord: https://svelte.dev/playground/hello-world?version=5.2.0#H4sIAAAAAAAAE8WSwY7UMAyGX8VEIzWVRq32WtoibogDHDhSDk3HYbOkcZW4LEOVd0dpuzMDO3eUQyz7t_3J9iJcP6KoxAe0luCZvD2BxJNhPOXiKLSxGET1dRF8npIuOcTxJev9NBXhJ1pOPtUHvOcfyDE6DqISdRi8mbjtXMdmnMgzLPDsDffKIkTQnkbItswyMHnM3iatRYZUGhrIVsarO0BzqSAXTVRBpomyI6jeV-Bma2Oe1K7jsoRDBctudmw0yEMoNBE0TQOZ6n9n-U2840MoVO9T20DjDrOGIqANeF-bet4odyteGVBrHFjKHJr2v-HkG88dmG2wswuzggZCEWaV9qZQSlJPt7qNmdTTXejtpegr6PRumf-VXphX4WZc1tixR569A_k3y0os8z0vrv-aVJfXu3P140O7XfuSTiq-qcvHh7Zz9dQuH798_lQE9sZ9N_osDyGPdTmloJqZyQG5wZrhR7PsrV_W9Xpx8G67Q6j2mcTYjnQy-lyXW7FWHAXjLxYV-xnjt_gHkDu2ZI0DAAA=

    $effect(() => {
        let unsub = s.subscribe((obj) => {
            if (obj.foo === 'baz') {
                obj.bar = 'some';
            } else {
                obj.bar = null;
            }
        });

        return () => {
            unsub();
        };
    });

Is there a better way to do this?