From e01776401d7cf6518f4822beb3e7ba12a90c96d3 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Mon, 29 Apr 2024 22:50:59 +0100 Subject: [PATCH] fix: ensure no data loss occurs when using reactive Set methods (#11385) --- .changeset/honest-pans-kick.md | 5 +++++ packages/svelte/src/reactivity/set.js | 11 ++++++++--- packages/svelte/src/reactivity/set.test.ts | 20 ++++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 .changeset/honest-pans-kick.md diff --git a/.changeset/honest-pans-kick.md b/.changeset/honest-pans-kick.md new file mode 100644 index 0000000000..6f7fc09b7f --- /dev/null +++ b/.changeset/honest-pans-kick.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: ensure no data loss occurs when using reactive Set methods diff --git a/packages/svelte/src/reactivity/set.js b/packages/svelte/src/reactivity/set.js index 7466885366..0a4963f839 100644 --- a/packages/svelte/src/reactivity/set.js +++ b/packages/svelte/src/reactivity/set.js @@ -51,8 +51,11 @@ export class ReactiveSet extends Set { // @ts-ignore proto[method] = function (...v) { get(this.#version); + // We don't populate the underlying Set, so we need to create a clone using + // our internal values and then pass that to the method. + var clone = new Set(this.values()); // @ts-ignore - return set_proto[method].apply(this, v); + return set_proto[method].apply(clone, v); }; } @@ -60,9 +63,11 @@ export class ReactiveSet extends Set { // @ts-ignore proto[method] = function (...v) { get(this.#version); - + // We don't populate the underlying Set, so we need to create a clone using + // our internal values and then pass that to the method. + var clone = new Set(this.values()); // @ts-ignore - var set = /** @type {Set} */ (set_proto[method].apply(this, v)); + var set = /** @type {Set} */ (set_proto[method].apply(clone, v)); return new ReactiveSet(set); }; } diff --git a/packages/svelte/src/reactivity/set.test.ts b/packages/svelte/src/reactivity/set.test.ts index a855ede6b3..5226014518 100644 --- a/packages/svelte/src/reactivity/set.test.ts +++ b/packages/svelte/src/reactivity/set.test.ts @@ -86,3 +86,23 @@ test('set.delete(...)', () => { assert.deepEqual(Array.from(set.values()), [1, 2]); }); + +test('set.forEach()', () => { + const set = new ReactiveSet([1, 2, 3, 4, 5]); + + const log: any = []; + + const cleanup = effect_root(() => { + render_effect(() => { + set.forEach((v) => log.push(v)); + }); + }); + + flushSync(() => { + set.add(6); + }); + + assert.deepEqual(log, [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6]); + + cleanup(); +});