Skip to content

Commit d16f17c

Browse files
authored
fix: improve signal consumer tracking behavior (#10121)
1 parent 092370b commit d16f17c

File tree

4 files changed

+68
-1
lines changed

4 files changed

+68
-1
lines changed

.changeset/loud-cheetahs-flow.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: improve signal consumer tracking behavior

packages/svelte/src/internal/client/runtime.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,10 +456,14 @@ function remove_consumer(signal, dependency, remove_unowned) {
456456
function remove_consumers(signal, start_index, remove_unowned) {
457457
const dependencies = signal.d;
458458
if (dependencies !== null) {
459+
const active_dependencies = start_index === 0 ? null : dependencies.slice(0, start_index);
459460
let i;
460461
for (i = start_index; i < dependencies.length; i++) {
461462
const dependency = dependencies[i];
462-
remove_consumer(signal, dependency, remove_unowned);
463+
// Avoid removing a consumer if we know that it is active (start_index will not be 0)
464+
if (active_dependencies === null || !active_dependencies.includes(dependency)) {
465+
remove_consumer(signal, dependency, remove_unowned);
466+
}
463467
}
464468
}
465469
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
html: `<button>Add Item</button>`,
6+
7+
async test({ assert, target }) {
8+
const [btn1] = target.querySelectorAll('button');
9+
10+
flushSync(() => {
11+
btn1.click();
12+
btn1.click();
13+
});
14+
15+
assert.htmlEqual(
16+
target.innerHTML,
17+
`<button>Add Item</button><button>Index 0\n|\nItem 0</button><button>Index 1\n|\nItem 1</button>`
18+
);
19+
20+
let [btn2, btn3, btn4] = target.querySelectorAll('button');
21+
22+
flushSync(() => {
23+
btn4.click();
24+
btn3.click();
25+
});
26+
27+
assert.htmlEqual(target.innerHTML, `<button>Add Item</button>`);
28+
29+
let [btn5] = target.querySelectorAll('button');
30+
31+
flushSync(() => {
32+
btn5.click();
33+
});
34+
35+
assert.htmlEqual(
36+
target.innerHTML,
37+
`<button>Add Item</button><button>Index 0\n|\nItem 2</button>`
38+
);
39+
}
40+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<script>
2+
let arr = $state([]);
3+
let counter = 0
4+
5+
function addItem() {
6+
arr.push(`${counter++}`)
7+
}
8+
9+
function removeItem(i) {
10+
arr.splice(i, 1)
11+
}
12+
</script>
13+
14+
<button onclick={addItem}>Add Item</button>
15+
16+
{#each arr as item, i}
17+
<button onclick={() => removeItem(i)}>Index {i} | Item {item}</button>
18+
{/each}

0 commit comments

Comments
 (0)