Skip to content

Commit 10ab317

Browse files
committed
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.
1 parent dad0284 commit 10ab317

File tree

2 files changed

+82
-5
lines changed

2 files changed

+82
-5
lines changed

src/runtime/store/index.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type Updater<T> = (value: T) => T;
1313
type Invalidator<T> = (value?: T) => void;
1414

1515
/** Start and stop notification callbacks. */
16-
export type StartStopNotifier<T> = (set: Subscriber<T>) => Unsubscriber | void;
16+
export type StartStopNotifier<T> = (set: Subscriber<T>, update?: (fn: Updater<T>) => void) => Unsubscriber | void;
1717

1818
/** Readable interface for subscribing. */
1919
export interface Readable<T> {
@@ -92,7 +92,7 @@ export function writable<T>(value?: T, start: StartStopNotifier<T> = noop): Writ
9292
const subscriber: SubscribeInvalidateTuple<T> = [run, invalidate];
9393
subscribers.add(subscriber);
9494
if (subscribers.size === 1) {
95-
stop = start(set) || noop;
95+
stop = start(set, update) || noop;
9696
}
9797
run(value);
9898

@@ -125,7 +125,7 @@ type StoresValues<T> = T extends Readable<infer U> ? U :
125125
*/
126126
export function derived<S extends Stores, T>(
127127
stores: S,
128-
fn: (values: StoresValues<S>, set: (value: T) => void) => Unsubscriber | void,
128+
fn: (values: StoresValues<S>, set: Subscriber<T>, update?: (fn: Updater<T>) => void) => Unsubscriber | void,
129129
initial_value?: T
130130
): Readable<T>;
131131

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

164164
const auto = fn.length < 2;
165165

166-
return readable(initial_value, (set) => {
166+
return readable(initial_value, (set, update) => {
167167
let inited = false;
168168
const values = [];
169169

@@ -175,7 +175,7 @@ export function derived<T>(stores: Stores, fn: Function, initial_value?: T): Rea
175175
return;
176176
}
177177
cleanup();
178-
const result = fn(single ? values[0] : values, set);
178+
const result = fn(single ? values[0] : values, set, update);
179179
if (auto) {
180180
set(result as T);
181181
} else {

test/store/index.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,50 @@ describe('store', () => {
128128
assert.deepEqual(values, [0, 1, 2]);
129129
});
130130

131+
it('passes an optional update function', () => {
132+
let running;
133+
let tick;
134+
let add;
135+
136+
const store = readable(undefined, (set, update) => {
137+
tick = set;
138+
running = true;
139+
add = n => update(value => value + n);
140+
141+
set(0);
142+
143+
return () => {
144+
tick = () => { };
145+
add = _ => { };
146+
running = false;
147+
};
148+
});
149+
150+
assert.ok(!running);
151+
152+
const values = [];
153+
154+
const unsubscribe = store.subscribe(value => {
155+
values.push(value);
156+
});
157+
158+
assert.ok(running);
159+
tick(1);
160+
tick(2);
161+
add(3);
162+
add(4);
163+
tick(5);
164+
add(6);
165+
166+
unsubscribe();
167+
168+
assert.ok(!running);
169+
tick(7);
170+
add(8);
171+
172+
assert.deepEqual(values, [0, 1, 2, 5, 9, 5, 11]);
173+
});
174+
131175
it('creates an undefined readable store', () => {
132176
const store = readable();
133177
const values = [];
@@ -231,6 +275,39 @@ describe('store', () => {
231275
assert.deepEqual(values, [0, 2, 4]);
232276
});
233277

278+
it('passes optional set and update functions', () => {
279+
const number = writable(1);
280+
const evensAndSquaresOf4 = derived(number, (n, set, update) => {
281+
if (n % 2 === 0) set(n);
282+
if (n % 4 === 0) update(n => n * n);
283+
}, 0);
284+
285+
const values = [];
286+
287+
const unsubscribe = evensAndSquaresOf4.subscribe(value => {
288+
values.push(value);
289+
});
290+
291+
number.set(2);
292+
number.set(3);
293+
number.set(4);
294+
number.set(5);
295+
number.set(6);
296+
assert.deepEqual(values, [0, 2, 4, 16, 6]);
297+
298+
number.set(7);
299+
number.set(8);
300+
number.set(9);
301+
number.set(10);
302+
assert.deepEqual(values, [0, 2, 4, 16, 6, 8, 64, 10]);
303+
304+
unsubscribe();
305+
306+
number.set(11);
307+
number.set(12);
308+
assert.deepEqual(values, [0, 2, 4, 16, 6, 8, 64, 10]);
309+
});
310+
234311
it('prevents glitches', () => {
235312
const lastname = writable('Jekyll');
236313
const firstname = derived(lastname, n => n === 'Jekyll' ? 'Henry' : 'Edward');

0 commit comments

Comments
 (0)