Skip to content

Commit

Permalink
Pass update function to store setup callbacks
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rmunn committed Sep 21, 2021
1 parent dad0284 commit 10ab317
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 5 deletions.
10 changes: 5 additions & 5 deletions src/runtime/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type Updater<T> = (value: T) => T;
type Invalidator<T> = (value?: T) => void;

/** 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. */
export interface Readable<T> {
Expand Down Expand Up @@ -92,7 +92,7 @@ export function writable<T>(value?: T, start: StartStopNotifier<T> = noop): Writ
const subscriber: SubscribeInvalidateTuple<T> = [run, invalidate];
subscribers.add(subscriber);
if (subscribers.size === 1) {
stop = start(set) || noop;
stop = start(set, update) || noop;
}
run(value);

Expand Down Expand Up @@ -125,7 +125,7 @@ type StoresValues<T> = T extends Readable<infer U> ? U :
*/
export function derived<S extends Stores, T>(
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
): Readable<T>;

Expand Down Expand Up @@ -163,7 +163,7 @@ export function derived<T>(stores: Stores, fn: Function, initial_value?: T): Rea

const auto = fn.length < 2;

return readable(initial_value, (set) => {
return readable(initial_value, (set, update) => {
let inited = false;
const values = [];

Expand All @@ -175,7 +175,7 @@ export function derived<T>(stores: Stores, fn: Function, initial_value?: T): Rea
return;
}
cleanup();
const result = fn(single ? values[0] : values, set);
const result = fn(single ? values[0] : values, set, update);
if (auto) {
set(result as T);
} else {
Expand Down
77 changes: 77 additions & 0 deletions test/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,50 @@ describe('store', () => {
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', () => {
const store = readable();
const values = [];
Expand Down Expand Up @@ -231,6 +275,39 @@ describe('store', () => {
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', () => {
const lastname = writable('Jekyll');
const firstname = derived(lastname, n => n === 'Jekyll' ? 'Henry' : 'Edward');
Expand Down

0 comments on commit 10ab317

Please sign in to comment.