diff --git a/packages/solid/src/reactive/signal.ts b/packages/solid/src/reactive/signal.ts index a7b4995ef..4527ed328 100644 --- a/packages/solid/src/reactive/signal.ts +++ b/packages/solid/src/reactive/signal.ts @@ -86,6 +86,7 @@ export interface SignalState extends SourceMapValue { value: T; observers: Computation[] | null; observerSlots: number[] | null; + lastObserver: Computation | null; tValue?: T; comparator?: (prev: T, next: T) => boolean; // development-only @@ -236,6 +237,7 @@ export function createSignal( value, observers: null, observerSlots: null, + lastObserver: null, comparator: options.equals || undefined }; @@ -257,7 +259,10 @@ export function createSignal( return writeSignal(s, value); }; - return [readSignal.bind(s), setter]; + const result = [readSignal.bind(s), setter] as Signal; + if (IS_DEV) (result as any).state = s; + + return result; } export interface BaseOptions { @@ -1305,7 +1310,8 @@ export function readSignal(this: SignalState | Memo) { Updates = updates; } } - if (Listener) { + if (Listener && this.lastObserver !== Listener) { + this.lastObserver = Listener; const sSlot = this.observers ? this.observers.length : 0; if (!Listener.sources) { Listener.sources = [this]; @@ -1691,6 +1697,7 @@ function cleanNode(node: Owner) { source.observerSlots![index] = s; } } + source.lastObserver = null; } } diff --git a/packages/solid/test/signals.spec.ts b/packages/solid/test/signals.spec.ts index 8e23534bf..9dcf1e1d8 100644 --- a/packages/solid/test/signals.spec.ts +++ b/packages/solid/test/signals.spec.ts @@ -605,6 +605,25 @@ describe("catchError", () => { expect(errored).toBe(true); }); + describe("Repeatedly read the signal", () => { + test("Signal repeated read in for loop", () => { + const a = createSignal(0); + const dispose = createRoot(dispose => { + createEffect(() => { + for (let i = 0; i < 1000; i++) { + a[0](); + } + }); + return dispose; + }); + expect((a as any).state.observers.length).toBe(1); + expect((a as any).state.observerSlots.length).toBe(1); + expect((a as any).state.observers[0].sources.length).toBe(1); + expect((a as any).state.observers[0].sourceSlots.length).toBe(1); + dispose(); + }); + }); + test("In nested memo", () => { let errored = false; expect(() =>