diff --git a/src/index.ts b/src/index.ts index 3dae5b4..6f6558b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,7 @@ export function derive(deriveFn: DeriveFn): StoreApi { const listeners = new Set(); const subscriptions = new Map void>(); let state: State | undefined; + let dependencies: Map | undefined; let invalidated = true; const invalidate = () => { if (invalidated) { @@ -26,30 +27,40 @@ export function derive(deriveFn: DeriveFn): StoreApi { if (!invalidated) { return state as State; } - const dependencies = new Set(); - const get = (store?: StoreApi) => { - if (!store) { - return state; - } - dependencies.add(store); - return store.getState(); - }; - state = deriveFn(get as unknown as Getter); - invalidated = false; + if ( + !dependencies || + Array.from(dependencies).some( + ([store, value]) => !Object.is(store.getState(), value), + ) + ) { + const newDependencies = new Map(); + const get = (store?: StoreApi) => { + if (!store) { + return state; + } + const s = store.getState(); + newDependencies.set(store, s); + return s; + }; + state = deriveFn(get as unknown as Getter); + dependencies = newDependencies; + } if (listeners.size) { + const deps = new Set(dependencies.keys()); subscriptions.forEach((unsubscribe, store) => { - if (dependencies.has(store)) { - dependencies.delete(store); + if (deps.has(store)) { + deps.delete(store); } else { unsubscribe(); subscriptions.delete(store); } }); - dependencies.forEach((store) => { + deps.forEach((store) => { subscriptions.set(store, store.subscribe(invalidate)); }); + invalidated = false; } - return state; + return state as State; }; const subscribe = (listener: Listener): (() => void) => { listeners.add(listener);