diff --git a/src/reactivity/utils/Subscriptions.ts b/src/reactivity/utils/Subscriptions.ts index 71a6537..a1563cf 100644 --- a/src/reactivity/utils/Subscriptions.ts +++ b/src/reactivity/utils/Subscriptions.ts @@ -3,7 +3,7 @@ import { Subscriber, _Signal } from "../types"; export class Subscriptions { private currentSubscriber: Subscriber | null = null; - private ancestors = new Map<_Signal, _Signal>(); + private ancestors = new MapSet<_Signal, _Signal>(); private subscriptions = new MapSet<_Signal, Subscriber>(); run(subscriber: Subscriber, fn: () => void): void { @@ -22,10 +22,12 @@ export class Subscriptions { } if (subscriber.derived) { - this.ancestors.set(subscriber.derived, signal); + this.ancestors.addTo(subscriber.derived, signal); } - this.subscriptions.addTo(this._getAncestor(signal), subscriber); + this._getAncestors(signal).forEach((ancestor) => { + this.subscriptions.addTo(ancestor, subscriber); + }); } executeAllSubscriptionsTo(signal: _Signal) { @@ -35,12 +37,12 @@ export class Subscriptions { .forEach((subscriber) => subscriber.execute()); } - private _getAncestor(signal: _Signal): _Signal { - const ancestor = this.ancestors.get(signal); - if (!ancestor) { - return signal; + private _getAncestors(signal: _Signal): _Signal[] { + const ancestors = this.ancestors.get(signal); + if (!ancestors || ancestors.length === 0) { + return [signal]; } - return this._getAncestor(ancestor); + return ancestors.flatMap((ancestor) => this._getAncestors(ancestor)); } } diff --git a/test/reactivity.test.ts b/test/reactivity.test.ts index 5977a27..a3099a9 100644 --- a/test/reactivity.test.ts +++ b/test/reactivity.test.ts @@ -188,4 +188,50 @@ describe("reactivity", () => { "14px 14pt", ]); }); + + it("derive from multiple signals", () => { + const calls: string[] = []; + const [count, setCount] = signal(1); + const [name, setName] = signal("First"); + const nameAndCount = d`${name} -> ${count}` + + effect(() => calls.push(nameAndCount())); + + setCount(5); + setName("Second"); + setName("Third"); + setCount(7); + + expect(calls).toEqual([ + "First -> 1", + "First -> 5", + "Second -> 5", + "Third -> 5", + "Third -> 7", + ]); + }); + + it("derive from multiple signals and other derivations", () => { + const calls: string[] = []; + const [count, setCount] = signal(1); + const [name, setName] = signal("First"); + const nameAndCount = d`${name} -> ${count}` + const sum = derive(0, () => count() + count()) + const sumText = d`${nameAndCount} + ${count} = ${sum}` + + effect(() => calls.push(sumText())); + + setCount(5); + setName("Second"); + setName("Third"); + setCount(7); + + expect(calls).toEqual([ + "First -> 1 + 1 = 2", + "First -> 5 + 5 = 10", + "Second -> 5 + 5 = 10", + "Third -> 5 + 5 = 10", + "Third -> 7 + 7 = 14", + ]); + }); }); diff --git a/vite.config.ts b/vite.config.ts index cd70838..78685cc 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -6,7 +6,7 @@ export default defineConfig({ environment: "jsdom", coverage: { reporter: ["text", "html"], - exclude: [ "index.ts", "examples/**" ], + exclude: [ "index.ts", "examples/**", "cdn/**" ], }, } });