Skip to content

Commit 92ea58b

Browse files
rChaozRich-Harris
andauthored
fix: don't eagerly execute deriveds on resume (#16150)
* Add failing test * Add {@const} test case * Fix the bug * Add yet another test case * Better fix * Changeset * simplify * this appears to be unnecessary --------- Co-authored-by: Rich Harris <rich.harris@vercel.com>
1 parent 113a3da commit 92ea58b

File tree

5 files changed

+57
-8
lines changed

5 files changed

+57
-8
lines changed

.changeset/poor-pumpkins-exercise.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: don't eagerly execute deriveds on resume

packages/svelte/src/internal/client/reactivity/effects.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ export function render_effect(fn) {
329329
/**
330330
* @param {(...expressions: any) => void | (() => void)} fn
331331
* @param {Array<() => any>} thunks
332+
* @param {<T>(fn: () => T) => Derived<T>} d
332333
* @returns {Effect}
333334
*/
334335
export function template_effect(fn, thunks = [], d = derived) {
@@ -598,15 +599,11 @@ function resume_children(effect, local) {
598599
if ((effect.f & INERT) === 0) return;
599600
effect.f ^= INERT;
600601

601-
// Ensure the effect is marked as clean again so that any dirty child
602-
// effects can schedule themselves for execution
603-
if ((effect.f & CLEAN) === 0) {
604-
effect.f ^= CLEAN;
605-
}
606-
607602
// If a dependency of this effect changed while it was paused,
608-
// schedule the effect to update
609-
if (check_dirtiness(effect)) {
603+
// schedule the effect to update. we don't use `check_dirtiness`
604+
// here because we don't want to eagerly recompute a derived like
605+
// `{#if foo}{foo.bar()}{/if}` if `foo` is now `undefined
606+
if ((effect.f & CLEAN) !== 0) {
610607
set_signal_status(effect, DIRTY);
611608
schedule_effect(effect);
612609
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
let { value } = $props()
3+
4+
const text = $derived(value.toString())
5+
6+
$effect(() => console.log(text))
7+
</script>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
async test({ assert, target, logs }) {
6+
const [btn1, btn2] = target.querySelectorAll('button');
7+
const [div] = target.querySelectorAll('div');
8+
9+
flushSync(() => btn1?.click());
10+
assert.htmlEqual(div.innerHTML, '123 123');
11+
assert.equal(div.inert, true);
12+
13+
flushSync(() => btn2?.click());
14+
assert.htmlEqual(div.innerHTML, '');
15+
assert.deepEqual(logs, ['123']);
16+
}
17+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<script>
2+
import Component from './Component.svelte';
3+
4+
let outer = $state(true);
5+
let inner = $state(123);
6+
7+
function outro() {
8+
return { duration: 100 };
9+
}
10+
</script>
11+
12+
{#if outer}
13+
<div out:outro>
14+
{#if inner}
15+
{@const text = inner.toString()}
16+
{text} {inner.toString()}
17+
<Component value={inner} />
18+
{/if}
19+
</div>
20+
{/if}
21+
22+
<button onclick={() => { outer = false; inner = undefined; }}>Set both to falsy</button>
23+
<button onclick={() => { outer = true }}>Set outer to truthy</button>

0 commit comments

Comments
 (0)