-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathconnectGlobalState.js
75 lines (61 loc) · 2.36 KB
/
connectGlobalState.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
import React from 'react';
// connectGlobalState ======================================================================= //
let _components = [];
let _globalState = {};
/**
* Set globalState using function setGlobalState
* @param WrappedComponent
*
* In wrapped component: just use this.globalState.varName
* by get value from globalState, we add watcher automatically to component
* and component will re-render only when this varName is changed from globalState
*
* For changing global state: use this.setGlobalState, everything just work like this.setState
*/
export function connectGlobalState(WrappedComponent) {
WrappedComponent.prototype.setGlobalState = async function(newState) {
// do not use array function, use 'function' instead for having 'this' pointing to WrappedComponent
let component = this;
let updatedAttrs = Object.keys(newState);
// If value is Promise then we have to wait for having value
let _update = new Promise(resolve => {
updatedAttrs.forEach(async (attr) => {
let newVal = newState[attr];
if (typeof (newVal) === 'object' && 'then' in newVal) {
newVal = await newVal;
}
component.globalState[attr] = newVal;
resolve();
});
});
// Wait for all value updated
await _update;
// Update only component which listens to updated attr
_components.forEach(_component => {
let shouldUpdate = false;
updatedAttrs.forEach(attr => {
if (_component._global.has(attr)) {
shouldUpdate = true;
}
});
shouldUpdate && _component.forceUpdate();
});
};
WrappedComponent.prototype.componentWillMount = function() {
let component = this;
component._global = new Set();
component.globalState = new Proxy({}, {
get: (target, name) => {
component._global.add(name);
return _globalState[name];
},
set: (target, name, value) => {
component._global.add(name);
_globalState[name] = value;
return true;
}
});
_components.push(component);
};
return (props) => <WrappedComponent {...props} />
}