|
@@ -1,5 +1,11 @@
|
|
|
import { useState, useEffect } from "react";
|
|
|
|
|
|
+const nameToHookName = name => "use" + name.chatAt(0).toUpperCase() + name.slice(1);
|
|
|
+
|
|
|
+const shallowEq = (x, y) => x === y;
|
|
|
+
|
|
|
+const mapValues = (src, fn) => Object.fromEntries(Object.entries(src).map(([key, val]) => [key, fn(val)]));
|
|
|
+
|
|
|
const createObservable = initial => {
|
|
|
let _val = initial;
|
|
|
let _listeners = [];
|
|
@@ -22,10 +28,6 @@ const createObservable = initial => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-const nameToHookName = name => "use" + name.chatAt(0).toUpperCase() + name.slice(1);
|
|
|
-
|
|
|
-const shallowEq = (x, y) => x === y;
|
|
|
-
|
|
|
const createHook = obs => {
|
|
|
// allow linters to pick this up as a hook
|
|
|
const useObservable = (equality = shallowEq) => {
|
|
@@ -36,30 +38,24 @@ const createHook = obs => {
|
|
|
return useObservable;
|
|
|
}
|
|
|
|
|
|
-const mapValues = (src, fn) => Object.fromEntries(Object.entries(src).map(([key, val]) => [key, fn(val)]));
|
|
|
+const mergeState = (store, hooks, newState) => {
|
|
|
+ Object.entries(newState).forEach(([key, newValue]) => {
|
|
|
+ const obs = store[key];
|
|
|
+ if (obs) {
|
|
|
+ obs._set(newValue);
|
|
|
+ } else {
|
|
|
+ const newObs = createObservable(newValue);
|
|
|
+ store[key] = newObs;
|
|
|
+ hooks[nameToHookName(key)] = createHook(newObs);
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
|
|
|
export const createStore = (initial, actions = {}) => {
|
|
|
- const store = {}; // maps keys to observables
|
|
|
+ const store = {};
|
|
|
const hooks = {};
|
|
|
-
|
|
|
- const mergeState = newState => {
|
|
|
- Object.entries(newState).forEach(([key, newValue]) => {
|
|
|
- const obs = store[key];
|
|
|
- if (obs) {
|
|
|
- obs._set(newValue);
|
|
|
- } else {
|
|
|
- const newObs = createObservable(newValue);
|
|
|
- store[key] = newObs;
|
|
|
- hooks[nameToHookName(key)] = createHook(newObs);
|
|
|
- }
|
|
|
- });
|
|
|
- };
|
|
|
-
|
|
|
- mergeState(initial);
|
|
|
-
|
|
|
- const dispatch = mapValues(actions, act => (...args) => mergeState(act(...args)));
|
|
|
-
|
|
|
+ const dispatch = mapValues(actions, act => (...args) => mergeState(store, hooks, act(...args)));
|
|
|
const selector = mapValues(store, obs => obs._get);
|
|
|
-
|
|
|
+ mergeState(store, hooks, initial);
|
|
|
return [hooks, dispatch, selector];
|
|
|
}
|