Skip to content

Commit

Permalink
fix(cache): restore deep deps for observed keys
Browse files Browse the repository at this point in the history
  • Loading branch information
smalluban committed Mar 30, 2020
1 parent 320e5a0 commit ee85006
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 3 deletions.
23 changes: 20 additions & 3 deletions src/cache.js
Expand Up @@ -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);
Expand All @@ -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);
}
});
Expand All @@ -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;
Expand Down Expand Up @@ -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);
});
}
Expand Down
33 changes: 33 additions & 0 deletions test/spec/cache.js
Expand Up @@ -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);

Expand Down

0 comments on commit ee85006

Please sign in to comment.