Pass update function to store setup callbacks

This non-breaking change allows more complex store logic to be
implemented, such as a derived store that accumulates a history of
its parent store's values.
pull/6750/head
Robin Munn 5 years ago
parent dad0284771
commit 10ab317c8c

@ -13,7 +13,7 @@ export type Updater<T> = (value: T) => T;
type Invalidator<T> = (value?: T) => void; type Invalidator<T> = (value?: T) => void;
/** Start and stop notification callbacks. */ /** Start and stop notification callbacks. */
export type StartStopNotifier<T> = (set: Subscriber<T>) => Unsubscriber | void; export type StartStopNotifier<T> = (set: Subscriber<T>, update?: (fn: Updater<T>) => void) => Unsubscriber | void;
/** Readable interface for subscribing. */ /** Readable interface for subscribing. */
export interface Readable<T> { export interface Readable<T> {
@ -92,7 +92,7 @@ export function writable<T>(value?: T, start: StartStopNotifier<T> = noop): Writ
const subscriber: SubscribeInvalidateTuple<T> = [run, invalidate]; const subscriber: SubscribeInvalidateTuple<T> = [run, invalidate];
subscribers.add(subscriber); subscribers.add(subscriber);
if (subscribers.size === 1) { if (subscribers.size === 1) {
stop = start(set) || noop; stop = start(set, update) || noop;
} }
run(value); run(value);
@ -125,7 +125,7 @@ type StoresValues<T> = T extends Readable<infer U> ? U :
*/ */
export function derived<S extends Stores, T>( export function derived<S extends Stores, T>(
stores: S, stores: S,
fn: (values: StoresValues<S>, set: (value: T) => void) => Unsubscriber | void, fn: (values: StoresValues<S>, set: Subscriber<T>, update?: (fn: Updater<T>) => void) => Unsubscriber | void,
initial_value?: T initial_value?: T
): Readable<T>; ): Readable<T>;
@ -163,7 +163,7 @@ export function derived<T>(stores: Stores, fn: Function, initial_value?: T): Rea
const auto = fn.length < 2; const auto = fn.length < 2;
return readable(initial_value, (set) => { return readable(initial_value, (set, update) => {
let inited = false; let inited = false;
const values = []; const values = [];
@ -175,7 +175,7 @@ export function derived<T>(stores: Stores, fn: Function, initial_value?: T): Rea
return; return;
} }
cleanup(); cleanup();
const result = fn(single ? values[0] : values, set); const result = fn(single ? values[0] : values, set, update);
if (auto) { if (auto) {
set(result as T); set(result as T);
} else { } else {

@ -128,6 +128,50 @@ describe('store', () => {
assert.deepEqual(values, [0, 1, 2]); assert.deepEqual(values, [0, 1, 2]);
}); });
it('passes an optional update function', () => {
let running;
let tick;
let add;
const store = readable(undefined, (set, update) => {
tick = set;
running = true;
add = n => update(value => value + n);
set(0);
return () => {
tick = () => { };
add = _ => { };
running = false;
};
});
assert.ok(!running);
const values = [];
const unsubscribe = store.subscribe(value => {
values.push(value);
});
assert.ok(running);
tick(1);
tick(2);
add(3);
add(4);
tick(5);
add(6);
unsubscribe();
assert.ok(!running);
tick(7);
add(8);
assert.deepEqual(values, [0, 1, 2, 5, 9, 5, 11]);
});
it('creates an undefined readable store', () => { it('creates an undefined readable store', () => {
const store = readable(); const store = readable();
const values = []; const values = [];
@ -231,6 +275,39 @@ describe('store', () => {
assert.deepEqual(values, [0, 2, 4]); assert.deepEqual(values, [0, 2, 4]);
}); });
it('passes optional set and update functions', () => {
const number = writable(1);
const evensAndSquaresOf4 = derived(number, (n, set, update) => {
if (n % 2 === 0) set(n);
if (n % 4 === 0) update(n => n * n);
}, 0);
const values = [];
const unsubscribe = evensAndSquaresOf4.subscribe(value => {
values.push(value);
});
number.set(2);
number.set(3);
number.set(4);
number.set(5);
number.set(6);
assert.deepEqual(values, [0, 2, 4, 16, 6]);
number.set(7);
number.set(8);
number.set(9);
number.set(10);
assert.deepEqual(values, [0, 2, 4, 16, 6, 8, 64, 10]);
unsubscribe();
number.set(11);
number.set(12);
assert.deepEqual(values, [0, 2, 4, 16, 6, 8, 64, 10]);
});
it('prevents glitches', () => { it('prevents glitches', () => {
const lastname = writable('Jekyll'); const lastname = writable('Jekyll');
const firstname = derived(lastname, n => n === 'Jekyll' ? 'Henry' : 'Edward'); const firstname = derived(lastname, n => n === 'Jekyll' ? 'Henry' : 'Edward');

Loading…
Cancel
Save