Skip to content

Commit f5f0c4e

Browse files
authored
Make ReactiveSet.clear() and ReactiveMap.clear() more efficient by only notifying listeners of existing members (#784)
2 parents 4af32ec + 1d1c686 commit f5f0c4e

File tree

6 files changed

+89
-13
lines changed

6 files changed

+89
-13
lines changed

.changeset/funny-baths-drive.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@solid-primitives/set": minor
3+
---
4+
5+
Avoid notifying non-existent members on Set.clear()

.changeset/red-islands-tickle.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@solid-primitives/map": minor
3+
---
4+
5+
Avoid notifying non-existent members on Map.clear()

packages/map/src/index.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,17 @@ export class ReactiveMap<K, V> extends Map<K, V> {
120120
}
121121

122122
clear(): void {
123-
if (super.size) {
124-
super.clear();
123+
if (super.size === 0) return;
124+
batch(() => {
125+
this.#keyTriggers.dirty($OBJECT);
126+
this.#valueTriggers.dirty($OBJECT);
127+
for (const key of super.keys()) {
128+
this.#keyTriggers.dirty(key);
129+
this.#valueTriggers.dirty(key);
130+
}
125131

126-
batch(() => {
127-
this.#keyTriggers.dirtyAll();
128-
this.#valueTriggers.dirtyAll();
129-
});
130-
}
132+
super.clear();
133+
});
131134
}
132135
}
133136

packages/map/test/index.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,45 @@ describe("ReactiveMap", () => {
378378

379379
dispose();
380380
});
381+
test(".clear() notifies only listeners of existing members", () =>
382+
createRoot(dispose => {
383+
const map = new ReactiveMap([
384+
[1, "a"],
385+
[2, "b"],
386+
[3, "c"],
387+
]);
388+
389+
const existingKey = vi.fn();
390+
createComputed(() => existingKey(map.has(2)));
391+
392+
const existingValue = vi.fn();
393+
createComputed(() => existingValue(map.get(2)));
394+
395+
const nonexistingKey = vi.fn();
396+
createComputed(() => nonexistingKey(map.has(4)));
397+
398+
const nonexistingValue = vi.fn();
399+
createComputed(() => nonexistingValue(map.get(4)));
400+
401+
expect(existingKey).toHaveBeenNthCalledWith(1, true);
402+
expect(existingValue).toHaveBeenNthCalledWith(1, "b");
403+
404+
expect(nonexistingKey).toHaveBeenNthCalledWith(1, false);
405+
expect(nonexistingValue).toHaveBeenNthCalledWith(1, undefined);
406+
407+
map.clear();
408+
409+
expect(existingKey).toHaveBeenCalledTimes(2);
410+
expect(existingKey).toHaveBeenNthCalledWith(2, false);
411+
412+
expect(existingValue).toHaveBeenCalledTimes(2);
413+
expect(existingValue).toHaveBeenNthCalledWith(2, undefined);
414+
415+
expect(nonexistingKey).toHaveBeenCalledTimes(1);
416+
expect(nonexistingValue).toHaveBeenCalledTimes(1);
417+
418+
dispose();
419+
}));
381420
});
382421

383422
describe("ReactiveWeakMap", () => {

packages/set/src/index.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,14 @@ export class ReactiveSet<T> extends Set<T> {
8888
}
8989

9090
clear(): void {
91-
if (super.size) {
91+
if (!super.size) return;
92+
batch(() => {
93+
this.#triggers.dirty($KEYS);
94+
for (const member of super.values()) {
95+
this.#triggers.dirty(member);
96+
}
9297
super.clear();
93-
94-
batch(() => {
95-
this.#triggers.dirtyAll();
96-
});
97-
}
98+
});
9899
}
99100
}
100101

packages/set/test/index.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,29 @@ describe("ReactiveSet", () => {
182182

183183
dispose();
184184
});
185+
186+
test("clear notifies only listeners of existing members", () =>
187+
createRoot(dispose => {
188+
const set = new ReactiveSet([1, 2, 3, 4]);
189+
190+
const existing = vi.fn();
191+
createComputed(() => existing(set.has(2)));
192+
193+
const nonexisting = vi.fn();
194+
createComputed(() => nonexisting(set.has(5)));
195+
196+
expect(existing).toHaveBeenNthCalledWith(1, true);
197+
expect(nonexisting).toHaveBeenNthCalledWith(1, false);
198+
199+
set.clear();
200+
201+
expect(existing).toHaveBeenCalledTimes(2);
202+
expect(existing).toHaveBeenNthCalledWith(2, false);
203+
204+
expect(nonexisting).toHaveBeenCalledTimes(1);
205+
206+
dispose();
207+
}));
185208
});
186209

187210
describe("ReactiveWeakSet", () => {

0 commit comments

Comments
 (0)