Skip to content

Commit 48fa658

Browse files
fix: lazily create sources for Set (#11946)
* fix: create sources for initial values of Set * fix: create sources lazily on Set * fix: avoid creating sources if sizes are the same * chore: add test for size of Set * create iterator lazily * tidy up test * oops --------- Co-authored-by: Rich Harris <[email protected]>
1 parent d7b7a9d commit 48fa658

File tree

4 files changed

+54
-54
lines changed

4 files changed

+54
-54
lines changed

.changeset/thin-spoons-float.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: create sources on read for Set

packages/svelte/src/reactivity/set.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export class ReactiveSet extends Set {
4747
for (const method of read_methods) {
4848
// @ts-ignore
4949
proto[method] = function (...v) {
50+
this.#read_all();
5051
get(this.#version);
5152
// @ts-ignore
5253
return set_proto[method].apply(this, v);
@@ -86,14 +87,30 @@ export class ReactiveSet extends Set {
8687
return super.has(value);
8788
}
8889

90+
#read_all() {
91+
var sources = this.#sources;
92+
93+
if (sources.size !== super.size) {
94+
for (let value of super.values()) {
95+
var s = sources.get(value);
96+
97+
if (s === undefined) {
98+
s = source(true);
99+
sources.set(value, s);
100+
}
101+
102+
get(s);
103+
}
104+
}
105+
}
106+
89107
/** @param {T} value */
90108
add(value) {
91109
var sources = this.#sources;
92110
var res = super.add(value);
93111
var s = sources.get(value);
94112

95113
if (s === undefined) {
96-
sources.set(value, source(true));
97114
set(this.#size, super.size);
98115
increment(this.#version);
99116
} else {
@@ -134,16 +151,19 @@ export class ReactiveSet extends Set {
134151
}
135152

136153
keys() {
154+
this.#read_all();
137155
get(this.#version);
138156
return super.keys();
139157
}
140158

141159
values() {
160+
this.#read_all();
142161
get(this.#version);
143162
return super.values();
144163
}
145164

146165
entries() {
166+
this.#read_all();
147167
get(this.#version);
148168
return super.entries();
149169
}
Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,28 @@
11
import { flushSync } from '../../../../src/index-client';
2-
import { test } from '../../test';
2+
import { ok, test } from '../../test';
33

44
export default test({
5-
html: `<button>add</button><button>delete</button><button>clear</button>`,
5+
html: `<button>delete initial</button><button>add</button><button>delete</button><button>clear</button><div id="output"><p>1</p><div>0</div></div>`,
66

77
test({ assert, target }) {
8-
const [btn, btn2, btn3] = target.querySelectorAll('button');
8+
const [btn, btn2, btn3, btn4] = target.querySelectorAll('button');
9+
const output = target.querySelector('#output');
10+
ok(output);
911

10-
flushSync(() => {
11-
btn?.click();
12-
});
12+
flushSync(() => btn?.click());
13+
assert.htmlEqual(output.innerHTML, `<p>0</p>`);
1314

14-
assert.htmlEqual(
15-
target.innerHTML,
16-
`<button>add</button><button>delete</button><button>clear</button><div>1</div>`
17-
);
15+
flushSync(() => btn2?.click());
16+
assert.htmlEqual(output.innerHTML, `<p>1</p><div>1</div>`);
1817

19-
flushSync(() => {
20-
btn?.click();
21-
});
18+
flushSync(() => btn2?.click());
19+
flushSync(() => btn2?.click());
20+
assert.htmlEqual(output.innerHTML, `<p>3</p><div>1</div><div>2</div><div>3</div>`);
2221

23-
flushSync(() => {
24-
btn?.click();
25-
});
22+
flushSync(() => btn3?.click());
23+
assert.htmlEqual(output.innerHTML, `<p>2</p><div>1</div><div>2</div>`);
2624

27-
assert.htmlEqual(
28-
target.innerHTML,
29-
`<button>add</button><button>delete</button><button>clear</button><div>1</div><div>2</div><div>3</div>`
30-
);
31-
32-
flushSync(() => {
33-
btn2?.click();
34-
});
35-
36-
assert.htmlEqual(
37-
target.innerHTML,
38-
`<button>add</button><button>delete</button><button>clear</button><div>1</div><div>2</div>`
39-
);
40-
41-
flushSync(() => {
42-
btn3?.click();
43-
});
44-
45-
assert.htmlEqual(
46-
target.innerHTML,
47-
`<button>add</button><button>delete</button><button>clear</button>`
48-
);
25+
flushSync(() => btn4?.click());
26+
assert.htmlEqual(output.innerHTML, `<p>0</p>`);
4927
}
5028
});
Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
<script>
2-
import {Set} from 'svelte/reactivity';
2+
import { Set } from 'svelte/reactivity';
33
4-
let state = new Set();
4+
let state = new Set([0]);
55
</script>
66

7-
<button onclick={() => {
8-
state.add(state.size + 1);
9-
}}>add</button>
7+
<button onclick={() => state.delete(0)}>delete initial</button>
8+
<button onclick={() => state.add(state.size + 1)}>add</button>
9+
<button onclick={() => state.delete(state.size)}>delete</button>
10+
<button onclick={() => state.clear()}>clear</button>
1011

11-
<button onclick={() => {
12-
state.delete(state.size);
13-
}}>delete</button>
12+
<div id="output">
13+
<p>{state.size}</p>
1414

15-
<button onclick={() => {
16-
state.clear();
17-
}}>clear</button>
18-
19-
{#each state as item}
20-
<div>{item}</div>
21-
{/each}
15+
{#each state as item}
16+
<div>{item}</div>
17+
{/each}
18+
</div>

0 commit comments

Comments
 (0)