UNPKG

2.85 kBPlain TextView Raw
1interface IHookzListener {
2 oldState: any;
3 run?: (state: any) => void;
4}
5
6interface IHookzStore {
7 state: any;
8 actions?: any;
9 listeners: IHookzListener[];
10 setState?: (newState: any, afterUpdateCallback: any) => void;
11}
12
13function setState(store: IHookzStore, newState: any, afterUpdateCallback: any) {
14 store.state = { ...store.state, ...newState };
15 store.listeners.forEach((listener: IHookzListener) => {
16 if (listener.run) {
17 listener.run(store.state);
18 }
19 });
20 if (afterUpdateCallback) {
21 afterUpdateCallback();
22 }
23}
24function useCustom(
25 store: IHookzStore,
26 React: any,
27 mapState: any,
28 mapActions: any,
29) {
30 const [, originalHook] = React.useState(Object.create(null));
31 const state = mapState ? mapState(store.state) : store.state;
32 const actions = React.useMemo(
33 () => (mapActions ? mapActions(store.actions) : store.actions),
34 [mapActions, store.actions],
35 );
36
37 React.useEffect(() => {
38 const newListener: IHookzListener = { oldState: {} };
39 newListener.run = mapState
40 ? (newState: any) => {
41 const mappedState = mapState(newState);
42 if (mappedState !== newListener.oldState) {
43 newListener.oldState = mappedState;
44 originalHook(mappedState);
45 }
46 }
47 : originalHook;
48 store.listeners.push(newListener);
49 if (newListener.run) {
50 newListener.run(store.state);
51 }
52 return () => {
53 store.listeners = store.listeners.filter(
54 (listener) => (listener) !== newListener,
55 );
56 };
57 }, []); // eslint-disable-line
58 return [state, actions];
59}
60
61function associateActions({ store, actions }: { store: any; actions: any }) {
62 const associatedActions = {};
63 Object.keys(actions).forEach((key) => {
64 if (typeof actions[key] === "function") {
65 // @ts-ignore
66 associatedActions[key] = actions[key].bind(null, store);
67 }
68 if (typeof actions[key] === "object") {
69 // @ts-ignore
70 associatedActions[key] = associateActions({
71 actions: actions[key],
72 store,
73 });
74 }
75 });
76 return associatedActions;
77}
78
79const useHookz = (
80 React: any,
81 initialState: any,
82 actions: any,
83 initializer?: any,
84) => {
85 const store: IHookzStore = { state: initialState, listeners: [] };
86 store.setState = setState.bind(null, store);
87 store.actions = associateActions({ store, actions });
88 if (initializer) {
89 initializer(store);
90 }
91 return useCustom.bind(null, store, React);
92};
93
94export default useHookz;