UNPKG

3.01 kBJavaScriptView Raw
1export const createStore = (state) => {
2 let listeners = [];
3 function unsubscribe(listener) {
4 let out = [];
5 for (let i = 0; i < listeners.length; i++) {
6 if (listeners[i] === listener) {
7 listener = null;
8 }
9 else {
10 out.push(listeners[i]);
11 }
12 }
13 listeners = out;
14 }
15 function setState(update, overwrite) {
16 state = overwrite ? update : Object.assign(Object.assign({}, state), update);
17 let currentListeners = listeners;
18 for (let i = 0; i < currentListeners.length; i++) {
19 currentListeners[i](state);
20 }
21 }
22 /**
23 * An observable state container, returned from {@link createStore}
24 * @name store
25 */
26 return {
27 get state() {
28 return state;
29 },
30 /**
31 * Create a bound copy of the given action function.
32 * The bound returned function invokes action() and persists the result back to the store.
33 * If the return value of `action` is a Promise, the resolved value will be used as state.
34 * @param {Function} action An action of the form `action(state, ...args) -> stateUpdate`
35 * @returns {Function} boundAction()
36 */
37 action(action) {
38 function apply(result) {
39 setState(result, false);
40 }
41 // Note: perf tests verifying this implementation: https://esbench.com/bench/5a295e6299634800a0349500
42 return function () {
43 let args = [state];
44 for (let i = 0; i < arguments.length; i++)
45 args.push(arguments[i]);
46 // @ts-ignore
47 let ret = action.apply(this, args);
48 if (ret != null) {
49 if (ret.then)
50 return ret.then(apply);
51 return apply(ret);
52 }
53 };
54 },
55 /**
56 * Apply a partial state object to the current state, invoking registered listeners.
57 * @param {Object} update An object with properties to be merged into state
58 * @param {Boolean} [overwrite=false] If `true`, update will replace state instead of being merged into it
59 */
60 setState,
61 /**
62 * Register a listener function to be called whenever state is changed. Returns an `unsubscribe()` function.
63 * @param {Function} listener A function to call when state changes. Gets passed the new state.
64 * @returns {Function} unsubscribe()
65 */
66 subscribe(listener) {
67 listeners.push(listener);
68 return () => {
69 unsubscribe(listener);
70 };
71 }
72 // /**
73 // * Remove a previously-registered listener function.
74 // * @param {Function} listener The callback previously passed to `subscribe()` that should be removed.
75 // * @function
76 // */
77 // unsubscribe,
78 };
79};