diff --git a/src/cache.js b/src/cache.js index c40f141f..7ab72c90 100644 --- a/src/cache.js +++ b/src/cache.js @@ -44,6 +44,17 @@ function dispatchDeep(entry) { if (entry.contexts) entry.contexts.forEach(dispatchDeep); } +function restoreObservedDeps(entry, deps) { + if (deps) { + deps.forEach(depEntry => { + entry.deps.add(depEntry); + if (!depEntry.contexts) depEntry.contexts = new Set(); + depEntry.contexts.add(entry); + restoreObservedDeps(entry, depEntry.deps); + }); + } +} + const contextStack = new Set(); export function get(target, key, getter) { const entry = getEntry(target, key); @@ -57,11 +68,11 @@ export function get(target, key, getter) { } contextStack.forEach(context => { - context.deps = context.deps || new Set(); + if (!context.deps) context.deps = new Set(); context.deps.add(entry); if (context.observed) { - entry.contexts = entry.contexts || new Set(); + if (!entry.contexts) entry.contexts = new Set(); entry.contexts.add(context); } }); @@ -82,6 +93,12 @@ export function get(target, key, getter) { entry.deps = undefined; const nextValue = getter(target, entry.value); + if (entry.observed && entry.deps) { + entry.deps.forEach(depEntry => { + restoreObservedDeps(entry, depEntry.deps); + }); + } + if (nextValue !== entry.value) { entry.state += 1; entry.value = nextValue; @@ -159,7 +176,7 @@ export function observe(target, key, getter, fn) { if (entry.deps) { entry.deps.forEach(depEntry => { - depEntry.contexts = depEntry.contexts || new Set(); + if (!depEntry.contexts) depEntry.contexts = new Set(); depEntry.contexts.add(entry); }); } diff --git a/test/spec/cache.js b/test/spec/cache.js index 2b83c02c..8ba08d5b 100644 --- a/test/spec/cache.js +++ b/test/spec/cache.js @@ -194,6 +194,39 @@ describe("cache:", () => { }); }); + it("runs callback when deep value changes", done => { + const getDeepDeep = () => get(target, "deepDeep", _); + const getDeepDep = () => get(target, "deep", getDeepDeep); + const getDep = () => get(target, "dep", getDeepDep); + const getOther = () => get(target, "other", _); + + set(target, "deepDeep", _, "one"); + + observe( + target, + "key", + () => { + getOther(); + getDep(); + return {}; + }, + spy, + ); + + requestAnimationFrame(() => { + expect(spy).toHaveBeenCalledTimes(1); + set(target, "other", _, "two"); + requestAnimationFrame(() => { + expect(spy).toHaveBeenCalledTimes(2); + set(target, "deepDeep", _, "three"); + requestAnimationFrame(() => { + expect(spy).toHaveBeenCalledTimes(3); + done(); + }); + }); + }); + }); + it("cleans emitter when unobserve", done => { const unobserve = observe(target, "key", _, spy);