Skip to content

Commit bbeafba

Browse files
committed
fixes #3191
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 #2955
1 parent 2761da6 commit bbeafba

File tree

3 files changed

+38
-7
lines changed

3 files changed

+38
-7
lines changed

src/runtime/store/index.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,15 @@ export function writable<T>(value: T, start: StartStopNotifier<T> = noop): Writa
6767
function set(new_value: T): void {
6868
if (safe_not_equal(value, new_value)) {
6969
value = new_value;
70-
if (!stop) {
71-
return; // not ready
70+
if (stop) { // store is ready
71+
subscribers.forEach((s) => s[1]());
72+
subscribers.forEach((s) => s[0](value));
7273
}
73-
subscribers.forEach((s) => s[1]());
74-
subscribers.forEach((s) => s[0](value));
7574
}
7675
}
7776

7877
function update(fn: Updater<T>): void {
79-
set(fn(value));
78+
return set(fn(value));
8079
}
8180

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

130129
const auto = fn.length < 2;
131130

131+
const subscribers: Array<Subscriber<T>> = [];
132132
const invalidators: Array<Invalidator<T>> = [];
133+
let value: T = initial_value;
133134

134135
const store = readable(initial_value, (set) => {
135136
let inited = false;
@@ -146,6 +147,11 @@ export function derived<T, S extends Stores>(
146147
const result = fn(single ? values[0] : values, set);
147148
if (auto) {
148149
set(result as T);
150+
const dirty = safe_not_equal(value, result);
151+
value = result as T;
152+
if (!dirty) {
153+
subscribers.forEach(s => s(value));
154+
}
149155
} else {
150156
cleanup = is_function(result) ? result as Unsubscriber : noop;
151157
}
@@ -176,6 +182,7 @@ export function derived<T, S extends Stores>(
176182

177183
return {
178184
subscribe(run: Subscriber<T>, invalidate: Invalidator<T> = noop): Unsubscriber {
185+
subscribers.push(run);
179186
invalidators.push(invalidate);
180187

181188
const unsubscribe = store.subscribe(run, invalidate);
@@ -189,4 +196,4 @@ export function derived<T, S extends Stores>(
189196
};
190197
}
191198
};
192-
}
199+
}

test/js/samples/bind-open/expected.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,4 @@ class Component extends SvelteComponent {
6666
}
6767
}
6868

69-
export default Component;
69+
export default Component;

test/store/index.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,30 @@ describe('store', () => {
233233
unsubscribe();
234234
});
235235

236+
it('derived dependency does not update and shared ancestor updates', () => {
237+
const root = writable({ a: 0, b:0 });
238+
const values = [];
239+
240+
const a = derived(root, $root => {
241+
return 'a' + $root.a;
242+
});
243+
244+
const b = derived([a, root], ([$a, $root]) => {
245+
return 'b' + $root.b + $a;
246+
});
247+
248+
const unsubscribe = b.subscribe(v => {
249+
values.push(v);
250+
});
251+
252+
assert.deepEqual(values, ['b0a0']);
253+
254+
root.set({ a: 0, b: 1 });
255+
assert.deepEqual(values, ['b0a0', 'b1a0']);
256+
257+
unsubscribe();
258+
});
259+
236260
it('is updated with safe_not_equal logic', () => {
237261
const arr = [0];
238262

0 commit comments

Comments
 (0)