Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Derived store reruns subscribers if it's value has not changed when synced.

All invalidators of subscribers are run on a derived store when invalidated.

See sveltejs#2955
  • Loading branch information
btakita committed Jul 23, 2019
1 parent 2761da6 commit bbeafba
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 7 deletions.
19 changes: 13 additions & 6 deletions src/runtime/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,15 @@ export function writable<T>(value: T, start: StartStopNotifier<T> = noop): Writa
function set(new_value: T): void {
if (safe_not_equal(value, new_value)) {
value = new_value;
if (!stop) {
return; // not ready
if (stop) { // store is ready
subscribers.forEach((s) => s[1]());
subscribers.forEach((s) => s[0](value));
}
subscribers.forEach((s) => s[1]());
subscribers.forEach((s) => s[0](value));
}
}

function update(fn: Updater<T>): void {
set(fn(value));
return set(fn(value));
}

function subscribe(run: Subscriber<T>, invalidate: Invalidator<T> = noop): Unsubscriber {
Expand Down Expand Up @@ -129,7 +128,9 @@ export function derived<T, S extends Stores>(

const auto = fn.length < 2;

const subscribers: Array<Subscriber<T>> = [];
const invalidators: Array<Invalidator<T>> = [];
let value: T = initial_value;

const store = readable(initial_value, (set) => {
let inited = false;
Expand All @@ -146,6 +147,11 @@ export function derived<T, S extends Stores>(
const result = fn(single ? values[0] : values, set);
if (auto) {
set(result as T);
const dirty = safe_not_equal(value, result);
value = result as T;
if (!dirty) {
subscribers.forEach(s => s(value));
}
} else {
cleanup = is_function(result) ? result as Unsubscriber : noop;
}
Expand Down Expand Up @@ -176,6 +182,7 @@ export function derived<T, S extends Stores>(

return {
subscribe(run: Subscriber<T>, invalidate: Invalidator<T> = noop): Unsubscriber {
subscribers.push(run);
invalidators.push(invalidate);

const unsubscribe = store.subscribe(run, invalidate);
Expand All @@ -189,4 +196,4 @@ export function derived<T, S extends Stores>(
};
}
};
}
}
2 changes: 1 addition & 1 deletion test/js/samples/bind-open/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,4 @@ class Component extends SvelteComponent {
}
}

export default Component;
export default Component;
24 changes: 24 additions & 0 deletions test/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,30 @@ describe('store', () => {
unsubscribe();
});

it('derived dependency does not update and shared ancestor updates', () => {
const root = writable({ a: 0, b:0 });
const values = [];

const a = derived(root, $root => {
return 'a' + $root.a;
});

const b = derived([a, root], ([$a, $root]) => {
return 'b' + $root.b + $a;
});

const unsubscribe = b.subscribe(v => {
values.push(v);
});

assert.deepEqual(values, ['b0a0']);

root.set({ a: 0, b: 1 });
assert.deepEqual(values, ['b0a0', 'b1a0']);

unsubscribe();
});

it('is updated with safe_not_equal logic', () => {
const arr = [0];

Expand Down

0 comments on commit bbeafba

Please sign in to comment.