Skip to content

Commit 58efac6

Browse files
committed
fix: ensure no data loss occurs when using reactive Set methods
1 parent 2754e4e commit 58efac6

File tree

3 files changed

+33
-3
lines changed

3 files changed

+33
-3
lines changed

.changeset/honest-pans-kick.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: ensure no data loss occurs when using reactive Set methods

packages/svelte/src/reactivity/set.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,23 @@ export class ReactiveSet extends Set {
5151
// @ts-ignore
5252
proto[method] = function (...v) {
5353
get(this.#version);
54+
// We don't populate the underlying Set, so we need to create a clone using
55+
// our internal values and then pass that to the method.
56+
var clone = new Set(this.values());
5457
// @ts-ignore
55-
return set_proto[method].apply(this, v);
58+
return set_proto[method].apply(clone, v);
5659
};
5760
}
5861

5962
for (const method of set_like_methods) {
6063
// @ts-ignore
6164
proto[method] = function (...v) {
6265
get(this.#version);
63-
66+
// We don't populate the underlying Set, so we need to create a clone using
67+
// our internal values and then pass that to the method.
68+
var clone = new Set(this.values());
6469
// @ts-ignore
65-
var set = /** @type {Set<T>} */ (set_proto[method].apply(this, v));
70+
var set = /** @type {Set<T>} */ (set_proto[method].apply(clone, v));
6671
return new ReactiveSet(set);
6772
};
6873
}

packages/svelte/src/reactivity/set.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,23 @@ test('set.delete(...)', () => {
8686

8787
assert.deepEqual(Array.from(set.values()), [1, 2]);
8888
});
89+
90+
test('set.forEach()', () => {
91+
const set = new ReactiveSet([1, 2, 3, 4, 5]);
92+
93+
const log: any = [];
94+
95+
const cleanup = effect_root(() => {
96+
render_effect(() => {
97+
set.forEach((v) => log.push(v));
98+
});
99+
});
100+
101+
flushSync(() => {
102+
set.add(6);
103+
});
104+
105+
assert.deepEqual(log, [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6]);
106+
107+
cleanup();
108+
});

0 commit comments

Comments
 (0)