Skip to content

Commit 388e3e6

Browse files
authored
fix: improve signal consumer removal logic (#9837)
1 parent e2dcdc2 commit 388e3e6

File tree

4 files changed

+97
-7
lines changed

4 files changed

+97
-7
lines changed

.changeset/rich-tables-sing.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 removal logic

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -382,13 +382,15 @@ function remove_consumer(signal, start_index, remove_unowned) {
382382
let consumers_length = 0;
383383
if (consumers !== null) {
384384
consumers_length = consumers.length - 1;
385-
if (consumers_length === 0) {
386-
dependency.c = null;
387-
} else {
388-
const index = consumers.indexOf(signal);
389-
// Swap with last element and then remove.
390-
consumers[index] = consumers[consumers_length];
391-
consumers.pop();
385+
const index = consumers.indexOf(signal);
386+
if (index !== -1) {
387+
if (consumers_length === 0) {
388+
dependency.c = null;
389+
} else {
390+
// Swap with last element and then remove.
391+
consumers[index] = consumers[consumers_length];
392+
consumers.pop();
393+
}
392394
}
393395
}
394396
if (remove_unowned && consumers_length === 0 && (dependency.f & UNOWNED) !== 0) {
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
async test({ assert, target }) {
6+
const [b1, b2] = target.querySelectorAll('button');
7+
flushSync(() => {
8+
b1.click();
9+
});
10+
11+
assert.htmlEqual(
12+
target.innerHTML,
13+
`<div><button>A</button><button>B</button></div><div>A</div>`
14+
);
15+
16+
flushSync(() => {
17+
b2.click();
18+
});
19+
20+
assert.htmlEqual(
21+
target.innerHTML,
22+
`<div><button>A</button><button>B</button></div><div>B\n12</div>`
23+
);
24+
25+
flushSync(() => {
26+
b1.click();
27+
});
28+
29+
assert.htmlEqual(
30+
target.innerHTML,
31+
`<div><button>A</button><button>B</button></div><div>A</div>`
32+
);
33+
34+
flushSync(() => {
35+
b2.click();
36+
});
37+
38+
assert.htmlEqual(
39+
target.innerHTML,
40+
`<div><button>A</button><button>B</button></div><div>B\n12</div>`
41+
);
42+
43+
flushSync(() => {
44+
b1.click();
45+
});
46+
47+
assert.htmlEqual(
48+
target.innerHTML,
49+
`<div><button>A</button><button>B</button></div><div>A</div>`
50+
);
51+
}
52+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<script context="module">
2+
class Things {
3+
tab = $state('A');
4+
5+
data = $state([{no: 1}, {no: 2}]);
6+
list = $derived(this.filter());
7+
8+
filter() {
9+
this.tab;
10+
return this.data;
11+
}
12+
}
13+
14+
const things = new Things();
15+
</script>
16+
17+
<div>
18+
<button onclick={() => things.tab = 'A'} >A</button>
19+
<button onclick={() => things.tab = 'B'} >B</button>
20+
</div>
21+
22+
<div>
23+
{#if things.tab === 'A'}
24+
A
25+
{:else}
26+
B
27+
{#each things.list as item}
28+
{item.no}
29+
{/each}
30+
{/if}
31+
</div>

0 commit comments

Comments
 (0)