Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

$effect doesn’t re-run after changing a $derived value it depends on #14976

Open
wjainek opened this issue Jan 10, 2025 · 3 comments · May be fixed by #14989
Open

$effect doesn’t re-run after changing a $derived value it depends on #14976

wjainek opened this issue Jan 10, 2025 · 3 comments · May be fixed by #14989
Assignees
Labels

Comments

@wjainek
Copy link

wjainek commented Jan 10, 2025

Describe the bug

If an $effect indirectly changes a $derived value it depends on, it doesn’t re-run. This is inconsistent with the simpler case where the $effect depends directly on the changed value.

Reproduction
The following code demonstrates the issue. In the diagram, dashed lines represent dependencies, and the dotted line a mutation.

// value --> doubled --> effect
//   ^                     .
//   .                     .
//   .......................

let value   = $state(1);
let doubled = $derived(value * 2);

$effect(() => {
  console.log(doubled);
  value = 10;
});

// Expected output: 2, 20
// Actual output:   2

Expected behavior
After mutating value inside the effect, the effect should be re-run since it depends on doubled, which in turn depends on value. The expected output is two log outputs: 2 followed by 20.

Actual behavior
The effect is only run once, producing a log output of 2.

Comparison case
Contrast this behavior to the simpler case, where the effect depends directly on value. Here, the effect is re-run as expected:

// value --> effect
//   ^         .
//   .         .
//   ...........

let value = $state(1);

$effect(() => {
  console.log(value);
  value = 10;
});

// Expected output: 1, 10
// Actual output:   1, 10

Reproduction

https://svelte.dev/playground/acd432616b63452d923e84109d62a23e?version=5.17.3

Logs

No response

System Info

System:
  OS: macOS 15.1.1
  CPU: (10) arm64 Apple M1 Max
  Memory: 179.77 MB / 64.00 GB
  Shell: 5.9 - /bin/zsh
Binaries:
  Node: 22.9.0 - /opt/homebrew/bin/node
  npm: 10.8.3 - /opt/homebrew/bin/npm
Browsers:
  Chrome: 131.0.6778.265
  Safari: 18.1.1
npmPackages:
  svelte: ^5.15.0 => 5.17.3

Severity

annoyance

@dummdidumm dummdidumm added the bug label Jan 10, 2025
@webJose
Copy link
Contributor

webJose commented Jan 10, 2025

How is this not creating an infinite loop? I mean, the expected result should be an infinte loop, even in the second case where no $derived is used.

Sorry, it's a constant 10.

@Leonidaz
Copy link

it seems to work with two separate effects

$effect(() => {
  console.log(doubled);
});

$effect(() => {
  value = 10;
});

also works with a tick():

$effect(() => {
  console.log(doubled);
  
  tick().then(() => value = 10);
});

@Ocean-OS
Copy link
Contributor

it seems to work with two separate effects

$effect(() => {
  console.log(doubled);
});

$effect(() => {
  value = 10;
});

also works with a tick():

$effect(() => {
  console.log(doubled);
  
  tick().then(() => value = 10);
});

The two separate effects working would make sense, since value's effect would not have doubled as a dependency. I don't quite remember/know if Svelte records writes inside of an effect, but either way, async effects stop recording halfway through, so the effect using tick has no connection with value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants