-
Notifications
You must be signed in to change notification settings - Fork 0
/
createStore.js
97 lines (86 loc) · 3.98 KB
/
createStore.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import React from 'react';
import stores from './stores';
function createStore(name, reducer, initialState = {}, timeoutDuration) {
const isReducerMode = typeof reducer === 'function';
stores[name] = {
state: isReducerMode ? initialState : reducer,
listeners: [],
isReducerMode
};
const store = stores[name];
let timeout;
return {
useStore: (mapStateFn) => {
const [state, setState] = React.useState(typeof mapStateFn === 'function' ? mapStateFn(store.state) : store.state);
const updateState = React.useCallback((newState) => {
setState((state) => {
if(typeof mapStateFn === 'function') {
const newMappedState = mapStateFn(newState);
if(state && newMappedState && typeof state === 'object' && typeof newMappedState === 'object') {
const isStateArray = Array.isArray(state);
const isMappedStateArray = Array.isArray(newMappedState);
if(isStateArray && isMappedStateArray) {
let shouldUpdate = false;
if(state.length !== newMappedState.length) {
shouldUpdate = true;
} else {
for(let i = 0; i < newMappedState.length; i++) {
if(newMappedState[i] !== state[i]) {
shouldUpdate = true;
break;
}
}
}
return shouldUpdate ? newMappedState : state;
} else if(!isStateArray && !isMappedStateArray) {
let shouldUpdate = false;
for(let i in newMappedState) {
if(newMappedState[i] !== state[i]) {
shouldUpdate = true;
break;
}
}
return shouldUpdate ? newMappedState : state;
}
}
}
return newState;
});
}, []);
// Add current hook into the listeners
const key = React.useRef(null);
if (key.current === null) {
key.current = Math.random();
store.listeners.push({key: key.current, updateState});
}
React.useEffect(() => {
return () => {
store.listeners = store.listeners.filter((item) => item.key !== key.current);
};
}, []);
const dispatch = React.useCallback((action) => {
const newState = isReducerMode ? reducer(store.state, action) : (
typeof action === 'function' ? action(store.state) : action
);
const oldState = store.state;
store.state = newState;
timeoutDuration && timeout && clearTimeout(timeout);
timeoutDuration && (
timeout = setTimeout(() => {
update(newState, oldState);
}, timeoutDuration)
) || update(newState, oldState);
}, []);
const update = React.useCallback((newState, oldState) => {
store.listeners.forEach(({updateState}) => {
updateState(newState, oldState);
});
}, []);
const getState = React.useCallback(() => {
return store.state;
}, []);
return [state, dispatch, getState];
}
};
}
export default createStore;