diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index dfb270dc97..fe981896b9 100644 --- a/site/content/docs/03-run-time.md +++ b/site/content/docs/03-run-time.md @@ -324,13 +324,13 @@ const time = readable(new Date(), set => { store = derived(a, callback: (a: any) => any) ``` ```js -store = derived(a, callback: (a: any, set: (value: any) => void) => void, initial_value: any) +store = derived(a, callback: (a: any, set: (value: any) => void) => void | () => void, initial_value: any) ``` ```js store = derived([a, ...b], callback: ([a: any, ...b: any[]]) => any) ``` ```js -store = derived([a, ...b], callback: ([a: any, ...b: any[]], set: (value: any) => void) => void, initial_value: any) +store = derived([a, ...b], callback: ([a: any, ...b: any[]], set: (value: any) => void) => void | () => void, initial_value: any) ``` --- @@ -359,6 +359,20 @@ const delayed = derived(a, ($a, set) => { }, 'one moment...'); ``` +If you return a function from the callback, it will be called when a) the callback runs again, or b) the last subscriber unsubscribes: + +```js +import { derived } from 'svelte/store'; + +const tick = derived(frequency, ($frequency, set) => { + const interval = setInterval(() => set(Date.now()), 1000 / frequency); + + return () => { + clearInterval(interval); + } +}, 'one moment...'); +``` + --- In both cases, an array of arguments can be passed as the first argument instead of a single store. diff --git a/store.mjs b/store.mjs index bc9bc46ed1..624ede3dde 100644 --- a/store.mjs +++ b/store.mjs @@ -51,11 +51,14 @@ export function derived(stores, fn, initial_value) { const values = []; let pending = 0; + let cleanup = noop; const sync = () => { if (pending) return; + cleanup(); const result = fn(single ? values[0] : values, set); if (auto) set(result); + else cleanup = result || noop; }; const unsubscribers = stores.map((store, i) => store.subscribe( @@ -74,6 +77,7 @@ export function derived(stores, fn, initial_value) { return function stop() { run_all(unsubscribers); + cleanup(); }; }); } diff --git a/test/store/index.js b/test/store/index.js index 44617d6d00..5f9176cffb 100644 --- a/test/store/index.js +++ b/test/store/index.js @@ -211,6 +211,37 @@ describe('store', () => { unsubscribe(); }); + + it('calls a cleanup function', () => { + const num = writable(1); + + const values = []; + const cleaned_up = []; + + const d = derived(num, ($num, set) => { + set($num * 2); + + return function cleanup() { + cleaned_up.push($num); + }; + }); + + num.set(2); + + const unsubscribe = d.subscribe(value => { + values.push(value); + }); + + num.set(3); + num.set(4); + + assert.deepEqual(values, [4, 6, 8]); + assert.deepEqual(cleaned_up, [2, 3]); + + unsubscribe(); + + assert.deepEqual(cleaned_up, [2, 3, 4]); + }); }); describe('get', () => {