diff --git a/bau/bau.js b/bau/bau.js index 39560ae0..bd72fbbe 100644 --- a/bau/bau.js +++ b/bau/bau.js @@ -52,6 +52,7 @@ export default function Bau(input) { let updateDom = (state, op) => { !_stateOps.length && _window.requestAnimationFrame(processDom); _stateOps.push([state, op]); + for (let l of state.listeners) l.state.dirty = true; }; const processDom = () => { @@ -249,10 +250,14 @@ export default function Bau(input) { rawVal: initVal, bindings: [], listeners: [], + dirty: false, __isState: true, get val() { let _state = this; _curDeps?.g?.add(_state); + if (_state.computed && _state.dirty) { + deriveInternal(_state.computed, _state); + } return ( _state.valProxy ?? ((_state.valProxy = isArrayOrObject(initVal) @@ -304,12 +309,13 @@ export default function Bau(input) { ) )) dep.listeners.push(listener); + state.dirty = false; }; let derive = (computed, options) => { let state = createState(undefined, options); + state.computed = computed; deriveInternal(computed, state); - state.computed = true; return state; }; diff --git a/bau/test/derive.test.js b/bau/test/derive.test.js index 66a77056..f686792e 100644 --- a/bau/test/derive.test.js +++ b/bau/test/derive.test.js @@ -115,4 +115,55 @@ describe("derive", async () => { assert.equal(b.val, 1); expect(spys).toHaveBeenCalledTimes(2); }); + + it("updates incrementally", () => { + const a = bau.state(false); + const b = bau.state(false); + const derived = bau.derive(() => { + if (!a.val) return 1; + if (!b.val) return 2; + return 3; + }); + + assert.equal(derived.val, 1); + a.val = true; + assert.equal(derived.val, 2); + b.val = true; + assert.equal(derived.val, 3); + }); + + it("updates when first null", () => { + const a = bau.state(false); + const b = bau.state(false); + const derived = bau.derive(() => { + if (!a.val) return null; + if (!b.val) return null; + return true; + }); + + assert.equal(derived.val, null); + a.val = true; + b.val = true; + assert.equal(derived.val, true); + }); + + it("does not call derive when non-dependencies change", () => { + const a = bau.state(0); + const b = bau.state(0); + let called = 0; + const derived = bau.derive(() => { + ++called; + return a.val; + }); + assert.equal(derived.val, 0); + assert.equal(derived.val, 0); + assert.equal(called, 1); + ++a.val; + assert.equal(derived.val, 1); + assert.equal(derived.val, 1); + assert.equal(called, 2); + ++b.val; + assert.equal(derived.val, 1); + assert.equal(called, 2); + }); });