diff --git a/bau/bau.js b/bau/bau.js index fcb89020..1544b952 100644 --- a/bau/bau.js +++ b/bau/bau.js @@ -301,14 +301,9 @@ export default function Bau(input) { state.val = runAndCaptureDeps(computed, deps); let listener = { computed, state }; - for (let dep of new Set( - [...deps.g].filter( - (dep) => - !deps.s.has(dep) && - dep.listeners.every((listener) => !deps.g.has(listener.state)) - ) - )) - dep.listeners.push(listener); + for (let dep of new Set([...deps.g].filter((dep) => !deps.s.has(dep)))) { + if (!dep.listeners.some((l) => l.state === state)) dep.listeners.push(listener); + } state.dirty = false; }; diff --git a/bau/test/derive.test.js b/bau/test/derive.test.js index 53d3ea45..73c8a6b7 100644 --- a/bau/test/derive.test.js +++ b/bau/test/derive.test.js @@ -162,4 +162,25 @@ describe("derive", async () => { assert.equal(derived.val, 1); assert.equal(called, 2); }); + + it("does not recompute more than once per update", async () => { + const a = bau.state(0); + let called = 0; + const d = bau.derive(() => { + called++; + return a.val + 1; + }); + // Initial compute + assert.strictEqual(d.val, 1); + assert.strictEqual(called, 1); + // Drive several recomputations to simulate potential duplicate subscriptions + a.val = 2; await sleep(); + a.val = 3; await sleep(); + a.val = 4; await sleep(); + const before = called; + // A single update should trigger exactly one recompute + a.val = 5; await sleep(); + assert.strictEqual(called - before, 1); + assert.strictEqual(d.val, 6); + }); });