Open
Description
Describe the problem
In Svelte 4, you can use this pattern to trigger side-effects:
<script>
let num = 0;
let timesChanged = 0;
$: num, timesChanged++;
</script>
<h1>Num: {num}</h1>
<h2>Times changed: {timesChanged}</h2>
<button on:click={() => (num++)}>Increment</button>
However, this becomes unwieldy with runes:
<script>
import { untrack } from 'svelte';
let num = $state(0);
let timesChanged = $state(0);
$effect(() => {
// I don't like this syntax - it's unclear what it's doing
num;
// If you forget the untrack(), you get an infinite loop
untrack(() => {
timesChanged++;
});
});
</script>
<h1>Num: {num}</h1>
<h2>Times changed: {timesChanged}</h2>
<button on:click={() => (num++)}>Increment</button>
Describe the proposed solution
Allow an opt-in manual tracking of dependencies:
(note: this could be a different rune, like $effect.explicit
)
<script>
let num = $state(0);
let timesChanged = $state(0);
$effect(() => {
timesChanged++;
}, [num]);
</script>
<h1>Num: {num}</h1>
<h2>Times changed: {timesChanged}</h2>
<button on:click={() => (num++)}>Increment</button>
Alternatives considered
- Don't migrate to runes
- Use the clunky solution above
- This can almost be implemented by the user:
export function explicitEffect(fn, deps) {
$effect(() => {
deps;
untrack(fn);
});
}
but this compiles to
explicitEffect(
() => {
$.increment(timesChanged);
},
[$.get(num)]
);
Importance
would make my life easier