Skip to content

Commit 5e6fed6

Browse files
authored
fix: depend on reads of deriveds created within reaction (async mode) (#16823)
* fix: depend on reads of deriveds created within reaction (async mode) As part of sveltejs/kit#14481 we discovered that deriveds created within reactions and reading from them in that same reaction is actually useful in some cases, as such a use case we couldn't imagine yet in #15564 has appeared. We think it's ultimately better to rerun on those cases, so we're going to make this change in async mode (that way the behavior doesn't change unless you have enabled the experimental flag) * fix tests
1 parent 7d9962a commit 5e6fed6

File tree

6 files changed

+119
-5
lines changed

6 files changed

+119
-5
lines changed

.changeset/gold-eels-lay.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: depend on reads of deriveds created within reaction (async mode)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import * as w from '../warnings.js';
2929
import { async_effect, destroy_effect } from './effects.js';
3030
import { inspect_effects, internal_set, set_inspect_effects, source } from './sources.js';
3131
import { get_stack } from '../dev/tracing.js';
32-
import { tracing_mode_flag } from '../../flags/index.js';
32+
import { async_mode_flag, tracing_mode_flag } from '../../flags/index.js';
3333
import { Boundary } from '../dom/blocks/boundary.js';
3434
import { component_context } from '../context.js';
3535
import { UNINITIALIZED } from '../../../constants.js';
@@ -231,7 +231,7 @@ export function async_derived(fn, location) {
231231
export function user_derived(fn) {
232232
const d = derived(fn);
233233

234-
push_reaction_value(d);
234+
if (!async_mode_flag) push_reaction_value(d);
235235

236236
return d;
237237
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
// In non-async mode we're not reacting to deriveds read in the same context they're defined in
6+
skip_no_async: true,
7+
test({ assert, target, logs }) {
8+
const [a, b] = target.querySelectorAll('button');
9+
10+
flushSync(() => a?.click());
11+
assert.htmlEqual(
12+
target.innerHTML,
13+
`
14+
<button>a</button>
15+
<button>b</button>
16+
<p>1/0</p
17+
`
18+
);
19+
20+
flushSync(() => a?.click());
21+
assert.htmlEqual(
22+
target.innerHTML,
23+
`
24+
<button>a</button>
25+
<button>b</button>
26+
<p>2/0</p
27+
`
28+
);
29+
30+
flushSync(() => b?.click());
31+
assert.htmlEqual(
32+
target.innerHTML,
33+
`
34+
<button>a</button>
35+
<button>b</button>
36+
<p>2/1</p
37+
`
38+
);
39+
40+
flushSync(() => b?.click());
41+
assert.htmlEqual(
42+
target.innerHTML,
43+
`
44+
<button>a</button>
45+
<button>b</button>
46+
<p>2/2</p
47+
`
48+
);
49+
50+
assert.deepEqual(logs, [
51+
// init
52+
'a',
53+
'b',
54+
'effect a',
55+
'effect b',
56+
// click a
57+
'a',
58+
'effect a',
59+
// click a
60+
'a',
61+
'effect a',
62+
// click b
63+
'a',
64+
'b',
65+
'effect a',
66+
'effect b',
67+
// click b
68+
'a',
69+
'b',
70+
'effect a',
71+
'effect b'
72+
]);
73+
}
74+
});
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<script>
2+
let object = $state.raw({ a: 0, b: 0 });
3+
4+
function a() {
5+
console.log('a');
6+
return object.a;
7+
}
8+
9+
function b() {
10+
console.log('b');
11+
let double = $derived(object.b)
12+
return double;
13+
}
14+
15+
$effect(() => {
16+
object.a;
17+
console.log('effect a');
18+
})
19+
20+
$effect(() => {
21+
const b = $derived(object.b);
22+
b;
23+
console.log('effect b');
24+
})
25+
</script>
26+
27+
<button onclick={() => object = { ...object, a: object.a + 1 }}>a</button>
28+
<button onclick={() => object = { ...object, b: object.b + 1 }}>b</button>
29+
30+
<p>{a()}/{b()}</p>

packages/svelte/tests/runtime-runes/samples/untrack-own-deriveds/_config.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ export default test({
1313
target.innerHTML,
1414
`
1515
<button>increment</button>
16-
<p>1/2</p
16+
<p>1/2</p>
17+
<p>1/2</p>
1718
`
1819
);
1920

20-
assert.deepEqual(logs, [0, 0]);
21+
assert.deepEqual(logs, [0, 0, 0, 0]);
2122
}
2223
});

packages/svelte/tests/runtime-runes/samples/untrack-own-deriveds/main.svelte

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@
1717
$effect(() => {
1818
foo = new Foo();
1919
});
20+
21+
let bar = $derived(new Foo());
2022
</script>
2123

22-
<button onclick={() => foo.increment()}>increment</button>
24+
<button onclick={() => {foo.increment(); bar.increment()}}>increment</button>
2325

2426
{#if foo}
2527
<p>{foo.value}/{foo.double}</p>
2628
{/if}
29+
30+
<p>{bar.value}/{bar.double}</p>

0 commit comments

Comments
 (0)