Skip to content

Commit d3a01bd

Browse files
authored
fix: always mark reactions of deriveds (#16457)
* tweak * fix * test * changeset
1 parent 53fdd0f commit d3a01bd

File tree

5 files changed

+98
-12
lines changed

5 files changed

+98
-12
lines changed

.changeset/angry-hornets-hug.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: always mark reactions of deriveds

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,9 @@ export function update_derived(derived) {
337337

338338
// don't mark derived clean if we're reading it inside a
339339
// cleanup function, or it will cache a stale value
340-
if (is_destroying_effect) return;
340+
if (is_destroying_effect) {
341+
return;
342+
}
341343

342344
if (batch_deriveds !== null) {
343345
batch_deriveds.set(derived, derived.v);

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

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,6 @@ function mark_reactions(signal, status) {
314314
var reaction = reactions[i];
315315
var flags = reaction.f;
316316

317-
// Skip any effects that are already dirty
318-
if ((flags & DIRTY) !== 0) continue;
319-
320317
// In legacy mode, skip the current effect to prevent infinite loops
321318
if (!runes && reaction === active_effect) continue;
322319

@@ -326,15 +323,15 @@ function mark_reactions(signal, status) {
326323
continue;
327324
}
328325

329-
set_signal_status(reaction, status);
326+
// don't set a DIRTY reaction to MAYBE_DIRTY
327+
if ((flags & DIRTY) === 0) {
328+
set_signal_status(reaction, status);
329+
}
330330

331-
// If the signal a) was previously clean or b) is an unowned derived, then mark it
332-
if ((flags & (CLEAN | UNOWNED)) !== 0) {
333-
if ((flags & DERIVED) !== 0) {
334-
mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY);
335-
} else {
336-
schedule_effect(/** @type {Effect} */ (reaction));
337-
}
331+
if ((flags & DERIVED) !== 0) {
332+
mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY);
333+
} else if ((flags & DIRTY) === 0) {
334+
schedule_effect(/** @type {Effect} */ (reaction));
338335
}
339336
}
340337
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { tick } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
async test({ assert, target }) {
6+
await tick();
7+
8+
const [a, b, update] = target.querySelectorAll('button');
9+
10+
assert.htmlEqual(
11+
target.innerHTML,
12+
`
13+
<button>a</button>
14+
<button>b</button>
15+
<button>0</button>
16+
<h1>a</h1>
17+
`
18+
);
19+
20+
b.click();
21+
await tick();
22+
assert.htmlEqual(
23+
target.innerHTML,
24+
`
25+
<button>a</button>
26+
<button>b</button>
27+
<button>0</button>
28+
<h1>b</h1>
29+
`
30+
);
31+
32+
update.click();
33+
await tick();
34+
assert.htmlEqual(
35+
target.innerHTML,
36+
`
37+
<button>a</button>
38+
<button>b</button>
39+
<button>1</button>
40+
<h1>b</h1>
41+
`
42+
);
43+
44+
a.click();
45+
await tick();
46+
assert.htmlEqual(
47+
target.innerHTML,
48+
`
49+
<button>a</button>
50+
<button>b</button>
51+
<button>1</button>
52+
<h1>a</h1>
53+
`
54+
);
55+
}
56+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<script>
2+
let object = $state(null);
3+
let count = $state(0);
4+
5+
const condition = $derived(object === null);
6+
</script>
7+
8+
<svelte:boundary>
9+
<button onclick={() => (object = null)}>a</button>
10+
<button onclick={() => (object = {})}>b</button>
11+
12+
<button onclick={async () => {
13+
count++;
14+
await Promise.resolve();
15+
object = {};
16+
}}>{await count}</button>
17+
18+
{#if condition}
19+
<h1>a</h1>
20+
{:else}
21+
<h1>b</h1>
22+
{/if}
23+
24+
{#snippet pending()}{/snippet}
25+
</svelte:boundary>
26+

0 commit comments

Comments
 (0)