From 127b61a4658c046f2a35136408b98fb832feaaf1 Mon Sep 17 00:00:00 2001 From: Jon Rouleau Date: Tue, 14 Mar 2023 04:46:49 -0500 Subject: [PATCH] fix: derived store restarting when unsubscribed from another store with a shared ancestor (#8368) Fixes #8364 --------- Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> --- src/runtime/store/index.ts | 10 +++++++--- test/store/index.ts | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/runtime/store/index.ts b/src/runtime/store/index.ts index ee277c6216..67c2bcb15c 100644 --- a/src/runtime/store/index.ts +++ b/src/runtime/store/index.ts @@ -164,7 +164,7 @@ export function derived(stores: Stores, fn: Function, initial_value?: T): Rea const auto = fn.length < 2; return readable(initial_value, (set) => { - let inited = false; + let started = false; const values = []; let pending = 0; @@ -188,7 +188,7 @@ export function derived(stores: Stores, fn: Function, initial_value?: T): Rea (value) => { values[i] = value; pending &= ~(1 << i); - if (inited) { + if (started) { sync(); } }, @@ -197,12 +197,16 @@ export function derived(stores: Stores, fn: Function, initial_value?: T): Rea }) ); - inited = true; + started = true; sync(); return function stop() { run_all(unsubscribers); cleanup(); + // We need to set this to false because callbacks can still happen despite having unsubscribed: + // Callbacks might already be placed in the queue which doesn't know it should no longer + // invoke this derived store. + started = false; }; }); } diff --git a/test/store/index.ts b/test/store/index.ts index 7e8bdb2f64..920cabdc39 100644 --- a/test/store/index.ts +++ b/test/store/index.ts @@ -407,6 +407,25 @@ describe('store', () => { const d = derived(fake_observable, _ => _); assert.equal(get(d), 42); }); + + it('doesn\'t restart when unsubscribed from another store with a shared ancestor', () => { + const a = writable(true); + let b_started = false; + const b = derived(a, (_, __) => { + b_started = true; + return () => { + assert.equal(b_started, true); + b_started = false; + }; + }); + const c = derived(a, ($a, set) => { + if ($a) return b.subscribe(set); + }); + + c.subscribe(() => { }); + a.set(false); + assert.equal(b_started, false); + }); }); describe('get', () => {