Skip to content

Allow opt-in explicit dependency tracking for $effect #9248

Open
@ottomated

Description

@ottomated

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions