Svelte 5: Reference to derived function does not trigger effect #13354
-
Describe the bugIn Svelte 4, it's possible to do:
The runes equivalent does not work:
If ReproductionLogsNo response System InfoSystem:
OS: macOS 14.7
CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Memory: 361.81 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.13.1 - ~/.nvm/versions/node/v20.13.1/bin/node
Yarn: 1.22.22 - ~/.nvm/versions/node/v20.13.1/bin/yarn
npm: 10.5.2 - ~/.nvm/versions/node/v20.13.1/bin/npm
pnpm: 9.11.0 - ~/.nvm/versions/node/v20.13.1/bin/pnpm
Browsers:
Brave Browser: 100.1.37.111
Chrome: 128.0.6613.139
Chrome Canary: 131.0.6728.0
Safari: 18.0
npmPackages:
svelte: ^5.0.0-next.251 => 5.0.0-next.251 Severityblocking an upgrade |
Beta Was this translation helpful? Give feedback.
Replies: 9 comments 10 replies
-
I think one question here is whether |
Beta Was this translation helpful? Give feedback.
-
In Svelte 5 you generally should not need this pattern of capturing variables in functions via Dependencies are automatically tracked across function boundaries, so the function itself not changing should not matter for practical applications. E.g. this does not work in Svelte 4 but just does in Svelte 5: <script>
let n = 1;
function double() {
return n * 2;
}
</script>
<button on:click={() => n++}>{n}</button>
Double: {double()} If you have a realistic use case where it does matter, please explain it. |
Beta Was this translation helpful? Give feedback.
-
And if you really really need something like this you can use <script>
let n = $state(0);
let func = $derived.by(() => {
n;
return () => n;
});
$effect(() => {
func, console.log('func changed'); // Effect does not run when n changes
});
</script>
<button onclick={() => n++}>Click</button> |
Beta Was this translation helpful? Give feedback.
-
As often, the question here is 'what are you actually trying to do?' |
Beta Was this translation helpful? Give feedback.
-
Maybe it's an outlier, but my use case does rely on triggering an effect when a function's dependencies change. In my svelte-canvas library, users define reactive functions that encapsulate pieces of canvas rendering logic. When any render function's dependencies change, the library clears the canvas and then reruns each render function. Here's a simple example in Svelte 4. The render functions could just rerun with every rAF tick, but that would cause wasteful renders where nothing has changed. @paoloricciuti's suggestion works, but it's extra boilerplate for users. Either solution feels like a compromise compared with what's possible in Svelte 4. |
Beta Was this translation helpful? Give feedback.
-
I think you can change your library to just call the render function in an effect...by doing so every reactive variable inside the function will be registered as a dependency |
Beta Was this translation helpful? Give feedback.
-
The render functions run in a specific order. If the changed function is called in an effect, that will happen first, and then trigger every other function to re-render in order (including the changed function, at its actual position in the sequence). The upshot is that each changed render function would run twice per frame instead of once. |
Beta Was this translation helpful? Give feedback.
-
Maybe I'm missing something but something like this could work I think I've used a set but you could just as well use an array if you want to insert in specific places. Basically the point is: you shouldn't use the effect to trigger the chained render but just call every render in an effect... everytime something changes the whole chain will be rerun |
Beta Was this translation helpful? Give feedback.
-
I'm converting this to a discussion, as this has moved into "how can I achieve my specific use-case" territory. |
Beta Was this translation helpful? Give feedback.
Maybe I'm missing something but something like this could work I think
I've used a set but you could just as well use an array if you want to insert in specific places. Basically the point is: you shouldn't use the effect to trigger the chained render but just call every render in an effect... everytime something changes the whole chain will be rerun