react-native-global-state-hooks 2.0.6 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"GlobalStore.d.ts","sourceRoot":"","sources":["../src/GlobalStore.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AAEnD,oBAAY,kBAAkB,GAAG;IAC/B,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAChC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAA;AAED,eAAO,MAAM,QAAQ,uDAUpB,CAAC;AAEF,qBAAa,WAAW,CACtB,MAAM,EACN,QAAQ,SAAS,MAAM,GAAG,IAAI,EAC9B,QAAQ,SAAS,YAAY,CAAC,uBAAuB,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAC3E,YAAW,YAAY,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC;IAS9D,SAAS,CAAC,KAAK,EAAE,MAAM;IACvB,SAAS,CAAC,OAAO,EAAE,QAAQ;IACpB,cAAc,EAAE,QAAQ;IAE/B;;MAEE;IACK,oBAAoB,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IAdzD,WAAW,EAAE,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAM;IAE5D,IAAW,cAAc,IAAI,OAAO,CAEnC;gBAGW,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,QAA2B,EACvC,cAAc,GAAE,QAA2B;IAElD;;MAEE;IACK,oBAAoB,GAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,MAAM,GAAG,IAAI,CAAc;IAG7E,OAAO,KAAK,wBAAwB,GAEnC;IAED,OAAO,CAAC,eAAe,CAAiC;IAExD,SAAS,CAAC,wBAAwB,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAQ;IAElE,SAAS,CAAC,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;cAIvC,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;cA2BpC,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;cAIxD,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAUlD,SAAS,CAAC,YAAY,QAAO,MAAM,CAAqC;IAEjE,OAAO,sRA2BZ;IAEK,gBAAgB,mLAGV,QAAQ,SAAS,MAAM,GAAG,QAAQ,MAAM,CAAC,GAAG,MAAM,oDAO7D;IAEF,OAAO,CAAC,kBAAkB,CAA0G;IAEpI,SAAS,KAAK,iBAAiB,IAAI,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,YAAY,CAAC,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAY3H;IAED;;MAEE;IACF,SAAS,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,MAAM,IAAI,EAAE,MAAM,CAAC,EAAE,CAAM;IAE7D,SAAS,CAAC,YAAY,6BAA8B,MAAM,KAAK,MAAM,WAoBnE;IAEF,SAAS,CAAC,+BAA+B,6BAAoC,MAAM,KAAK,MAAM,MAAI,QAAQ,MAAM,CAAC,CAK/G;IAEF;;MAEE;IACF,MAAM,CAAC,qBAAqB,aAM3B;IAED,SAAS,CAAC,UAAU,sHA0BlB;IAEK,oBAAoB,QAAa,QAAQ,IAAI,CAAC,CAIpD;CAEF;AAED,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"GlobalStore.d.ts","sourceRoot":"","sources":["../src/GlobalStore.ts"],"names":[],"mappings":"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"}
@@ -1,176 +1,309 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GlobalStore = exports.debounce = void 0;
4
- const tslib_1 = require("tslib");
3
+ exports.GlobalStore = void 0;
5
4
  const react_1 = require("react");
6
- const json_storage_formatter_1 = require("json-storage-formatter");
7
- const async_storage_1 = (0, tslib_1.__importDefault)(require("@react-native-async-storage/async-storage"));
8
- const debounce = (callback, wait = 300) => {
9
- let timer;
10
- return ((...args) => {
11
- clearTimeout(timer);
12
- timer = setTimeout(() => {
13
- callback(...args);
14
- }, wait);
15
- });
5
+ const GlobalStore_utils_1 = require("./GlobalStore.utils");
6
+ const throwWrongKeyOnActionCollectionConfig = (action_key) => {
7
+ throw new Error(`[WRONG CONFIGURATION!]: Every key inside the storeActionsConfig must be a higher order function that returns a function \n[${action_key}]: key is not a valid function, try something like this: \n{\n
8
+ ${action_key}: (param) => ({ setState, getState, setMetadata, getMetadata }) => {\n
9
+ setState((state) => ({ ...state, ...param }))\n
10
+ }\n
11
+ }\n`);
16
12
  };
17
- exports.debounce = debounce;
13
+ /**
14
+ * The GlobalStore class is the main class of the library and it is used to create a GlobalStore instances
15
+ * @template {TState} TState - The type of the state object
16
+ * @template {TMetadata} TMetadata - The type of the metadata object (optional) (default: null) no reactive information set to share with the subscribers
17
+ * @template {TStateSetter} TStateSetter - The type of the setterConfig object (optional) (default: null) if a configuration is passed, the hook will return an object with the actions then all the store manipulation will be done through the actions
18
+ * */
18
19
  class GlobalStore {
19
- constructor(state, actions = null, persistStoreAs = null,
20
20
  /**
21
- * This function can be used to format the data after it is loaded from the asyncStorage
22
- */
23
- onPersistStorageLoad = () => null) {
21
+ * Create a new instance of the GlobalStore
22
+ * @param {TState} state - The initial state
23
+ * @param {TMetadata} metadata - The metadata object (optional) (default: null) no reactive information set to share with the subscribers
24
+ * @param {TStateSetter} setterConfig - The actions configuration object (optional) (default: null) if not null the store manipulation will be done through the actions
25
+ * @param {GlobalStoreConfig<TState, TMetadata>} config - The configuration object (optional) (default: { metadata: null })
26
+ * @param {StateConfigCallbackParam<TState, TMetadata>} config.onInit - The callback to execute when the store is initialized (optional) (default: null)
27
+ * @param {StateConfigCallbackParam<TState, TMetadata>} config.onStateChanged - The callback to execute when the state is changed (optional) (default: null)
28
+ * @param {StateConfigCallbackParam<TState, TMetadata>} config.onSubscribed - The callback to execute when a subscriber is added (optional) (default: null)
29
+ * @param {StateConfigCallbackParam<TState, TMetadata>} config.computePreventStateChange - The callback to execute when the state is changed to compute if the state change should be prevented (optional) (default: null)
30
+ * */
31
+ constructor(state, metadata = null, setterConfig = null, config = {}) {
24
32
  this.state = state;
25
- this.actions = actions;
26
- this.persistStoreAs = persistStoreAs;
27
- this.onPersistStorageLoad = onPersistStorageLoad;
28
- this.subscribers = [];
29
- this.storedStateItem = undefined;
30
- this.getAsyncStoreItemPromise = null;
31
- this.getStateCopy = () => Object.freeze((0, json_storage_formatter_1.clone)(this.state));
33
+ this.metadata = metadata;
34
+ this.setterConfig = setterConfig;
35
+ this.config = config;
36
+ /**
37
+ * list of all the subscribers setState functions
38
+ * @template {TState} TState - The type of the state object
39
+ * */
40
+ this.subscribers = new Set();
41
+ /**
42
+ * execute once the store is created
43
+ * @template {TState} TState - The type of the state object
44
+ * @template {TMetadata} TMetadata - The type of the metadata object (optional) (default: null) no reactive information set to share with the subscribers
45
+ * @template {TStateSetter} TStateSetter - The type of the setterConfig object (optional) (default: null) if a configuration is passed, the hook will return an object with the actions then all the store manipulation will be done through the actions
46
+ * @param {StateConfigCallbackParam<TState, TMetadata, TStateSetter>} parameters - The parameters object brings the following properties: setState, getState, setMetadata, getMetadata
47
+ * @param {Dispatch<SetStateAction<TState>>} parameters.setState - The setState function to update the state
48
+ * @param {() => TState} parameters.getState - The getState function to get the state
49
+ * @param {Dispatch<SetStateAction<TMetadata>>} parameters.setMetadata - The setMetadata function to update the metadata
50
+ * @param {() => TMetadata} parameters.getMetadata - The getMetadata function to get the metadata
51
+ * */
52
+ this.onInit = null;
53
+ /**
54
+ * execute every time the state is changed
55
+ * @template {TState} TState - The type of the state object
56
+ * @template {TMetadata} TMetadata - The type of the metadata object (optional) (default: null) no reactive information set to share with the subscribers
57
+ * @template {TStateSetter} TStateSetter - The type of the setterConfig object (optional) (default: null) if a configuration is passed, the hook will return an object with the actions then all the store manipulation will be done through the actions
58
+ * @param {StateConfigCallbackParam<TState, TMetadata, TStateSetter>} parameters - The parameters object brings the following properties: setState, getState, setMetadata, getMetadata
59
+ * @param {Dispatch<SetStateAction<TState>>} parameters.setState - The setState function to update the state
60
+ * @param {() => TState} parameters.getState - The getState function to get the state
61
+ * @param {Dispatch<SetStateAction<TMetadata>>} parameters.setMetadata - The setMetadata function to update the metadata
62
+ * @param {() => TMetadata} parameters.getMetadata - The getMetadata function to get the metadata
63
+ * */
64
+ this.onStateChanged = null;
65
+ /**
66
+ * Execute each time a new component gets subscribed to the store
67
+ * @template {TState} TState - The type of the state object
68
+ * @template {TMetadata} TMetadata - The type of the metadata object (optional) (default: null) no reactive information set to share with the subscribers
69
+ * @template {TStateSetter} TStateSetter - The type of the setterConfig object (optional) (default: null) if a configuration is passed, the hook will return an object with the actions then all the store manipulation will be done through the actions
70
+ * @param {StateConfigCallbackParam<TState, TMetadata, TStateSetter>} parameters - The parameters object brings the following properties: setState, getState, setMetadata, getMetadata
71
+ * @param {Dispatch<SetStateAction<TState>>} parameters.setState - The setState function to update the state
72
+ * @param {() => TState} parameters.getState - The getState function to get the state
73
+ * @param {Dispatch<SetStateAction<TMetadata>>} parameters.setMetadata - The setMetadata function to update the metadata
74
+ * @param {() => TMetadata} parameters.getMetadata - The getMetadata function to get the metadata
75
+ * */
76
+ this.onSubscribed = null;
77
+ /**
78
+ * Execute everytime a state change is triggered and before the state is updated, it allows to prevent the state change by returning true
79
+ * @template {TState} TState - The type of the state object
80
+ * @template {TMetadata} TMetadata - The type of the metadata object (optional) (default: null) no reactive information set to share with the subscribers
81
+ * @template {TStateSetter} TStateSetter - The type of the setterConfig object (optional) (default: null) if a configuration is passed, the hook will return an object with the actions then all the store manipulation will be done through the actions
82
+ * @param {StateConfigCallbackParam<TState, TMetadata, TStateSetter>} parameters - The parameters object brings the following properties: setState, getState, setMetadata, getMetadata
83
+ * @param {Dispatch<SetStateAction<TState>>} parameters.setState - The setState function to update the state
84
+ * @param {() => TState} parameters.getState - The getState function to get the state
85
+ * @param {Dispatch<SetStateAction<TMetadata>>} parameters.setMetadata - The setMetadata function to update the metadata
86
+ * @param {() => TMetadata} parameters.getMetadata - The getMetadata function to get the metadata
87
+ * @returns {boolean} - true to prevent the state change, false to allow the state change
88
+ * */
89
+ this.computePreventStateChange = null;
90
+ this.onInitializeStore = () => {
91
+ const { onInit } = this;
92
+ const { onInit: onInitFromConfig } = this.config;
93
+ if (!onInit && !onInitFromConfig)
94
+ return;
95
+ const parameters = this.getConfigCallbackParam({});
96
+ onInit === null || onInit === void 0 ? void 0 : onInit(parameters);
97
+ onInitFromConfig === null || onInitFromConfig === void 0 ? void 0 : onInitFromConfig(parameters);
98
+ };
99
+ /**
100
+ * gets a clone of the state
101
+ * @returns {TState} - The state clone
102
+ * */
103
+ this.getStateClone = () => (0, GlobalStore_utils_1.clone)(this.state);
104
+ /**
105
+ * gets a clone of the metadata
106
+ * @returns {TMetadata} - The metadata clone
107
+ * */
108
+ this.getMetadataClone = () => (0, GlobalStore_utils_1.clone)(this.metadata);
109
+ /**
110
+ * set the state and update all the subscribers
111
+ * @param {StateSetter<TState>} setter - The setter function or the value to set
112
+ * @param {React.Dispatch<React.SetStateAction<TState>>} invokerSetState - The setState function of the component that invoked the state change (optional) (default: null) this is used to updated first the component that invoked the state change
113
+ * */
114
+ this.setState = ({ invokerSetState, state, }) => {
115
+ // update the state
116
+ this.state = state;
117
+ // execute first the callback of the component that invoked the state change
118
+ invokerSetState === null || invokerSetState === void 0 ? void 0 : invokerSetState(state);
119
+ // update all the subscribers
120
+ this.subscribers.forEach((setState) => {
121
+ if (setState === invokerSetState)
122
+ return;
123
+ setState(state);
124
+ });
125
+ };
126
+ /**
127
+ * Set the value of the metadata property, this is no reactive and will not trigger a re-render
128
+ * @param {StateSetter<TMetadata>} setter - The setter function or the value to set
129
+ * */
130
+ this.setMetadata = (setter) => {
131
+ const isSetterFunction = typeof setter === 'function';
132
+ const metadata = isSetterFunction
133
+ ? setter(this.getMetadataClone())
134
+ : setter;
135
+ this.metadata = metadata;
136
+ };
137
+ /**
138
+ * get the parameters object to pass to the callback functions (onInit, onStateChanged, onSubscribed, computePreventStateChange)
139
+ * this parameters object brings the following properties: setState, getState, setMetadata, getMetadata
140
+ * this parameter object allows to update the state, get the state, update the metadata, get the metadata
141
+ * @param {{ invokerSetState?: React.Dispatch<React.SetStateAction<TState>> }} parameters - The setState function of the component that invoked the state change (optional) (default: null) this is used to updated first the component that invoked the state change
142
+ * @returns {StateConfigCallbackParam<TState, TMetadata>} - The parameters object
143
+ * */
144
+ this.getConfigCallbackParam = ({ invokerSetState, }) => {
145
+ const { setMetadata, getMetadataClone: getMetadata, getStateClone: getState, } = this;
146
+ const setState = this.getSetStateWrapper({ invokerSetState });
147
+ const actions = this.getStoreActionsMap({});
148
+ return {
149
+ setMetadata,
150
+ getMetadata,
151
+ getState,
152
+ setState,
153
+ actions,
154
+ };
155
+ };
156
+ /**
157
+ * Returns a custom hook that allows to handle a global state
158
+ * @returns {[TState, TStateSetter, TMetadata]} - The state, the state setter or the actions map, the metadata
159
+ * */
32
160
  this.getHook = () => () => {
33
- const [value, setter] = (0, react_1.useState)(() => this.state);
161
+ const [value, invokerSetState] = (0, react_1.useState)(() => this.state);
34
162
  (0, react_1.useEffect)(() => {
35
- this.subscribers.push(setter);
36
- if (this.isPersistStore) {
37
- this.getAsyncStoreItem();
163
+ this.subscribers.add(invokerSetState);
164
+ const { onSubscribed } = this;
165
+ const { onSubscribed: onSubscribedFromConfig } = this.config;
166
+ if (onSubscribed || onSubscribedFromConfig) {
167
+ const parameters = this.getConfigCallbackParam({ invokerSetState });
168
+ onSubscribed === null || onSubscribed === void 0 ? void 0 : onSubscribed(parameters);
169
+ onSubscribedFromConfig === null || onSubscribedFromConfig === void 0 ? void 0 : onSubscribedFromConfig(parameters);
38
170
  }
39
171
  return () => {
40
- this.subscribers = this.subscribers.filter((hook) => setter !== hook);
172
+ this.subscribers.delete(invokerSetState);
41
173
  };
42
174
  }, []);
43
- return [
44
- value,
45
- this.stateOrchestrator,
46
- this.isStoredStateItemUpdated,
47
- ];
175
+ const stateOrchestrator = this.getStateOrchestrator(invokerSetState);
176
+ return [value, stateOrchestrator, this.getMetadataClone()];
48
177
  };
178
+ /**
179
+ * Returns an array with the a function to get the state, the state setter or the actions map, and a function to get the metadata
180
+ * @returns {[() => TState, TStateSetter, () => TMetadata]} - The state getter, the state setter or the actions map, the metadata getter
181
+ * */
49
182
  this.getHookDecoupled = () => {
50
- const valueWrapper = this.isPersistStore ? this.getAsyncStoreItem() : () => this.state;
51
- return [
52
- valueWrapper,
53
- this.stateOrchestrator,
54
- ];
183
+ const { getStateClone: getState, getMetadataClone: getMetadata } = this;
184
+ const stateOrchestrator = this.getStateOrchestrator();
185
+ return [getState, stateOrchestrator, getMetadata];
55
186
  };
56
- this._stateOrchestrator = null;
57
- this.globalSetter = (setter) => {
58
- // avoid perform multiple updates over the same state
59
- GlobalStore.batchedUpdates = GlobalStore.batchedUpdates.filter(([, hook]) => {
60
- const isSameHook = hook === this;
61
- if (isSameHook) {
62
- // eslint-disable-next-line no-console
63
- console.warn('You should try avoid call the same state-setter multiple times at one execution line');
64
- }
65
- return !isSameHook;
66
- });
67
- const newState = typeof setter === 'function' ? setter(this.getStateCopy()) : setter;
68
- this.state = newState;
69
- // batch store updates
70
- GlobalStore.batchedUpdates.push([() => this.subscribers.forEach((updateChild) => updateChild(newState)), this]);
71
- GlobalStore.ExecutePendingBatches();
187
+ /**
188
+ * returns a wrapper for the setState function that will update the state and all the subscribers
189
+ * @param {{ invokerSetState?: React.Dispatch<React.SetStateAction<TState>> }} parameters - The setState function of the component that invoked the state change (optional) (default: null) this is used to updated first the component that invoked the state change
190
+ * @returns {StateSetter<TState>} - The state setter
191
+ * */
192
+ this.getSetStateWrapper = ({ invokerSetState, } = {}) => {
193
+ const setState = (setter) => {
194
+ this.computeSetState({ invokerSetState, setter });
195
+ };
196
+ return setState;
72
197
  };
73
- this.globalSetterToPersistStoreAsync = (setter) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
74
- this.globalSetter(setter);
75
- yield this.setAsyncStoreItem();
76
- return this.state;
77
- });
78
- this.getActions = () => {
79
- const actions = this.actions;
80
- // Setter is allways async because of the render batch
81
- // but we are typing the setter as synchronous to avoid the developer has extra complexity that useState do not handle
82
- const setter = this.isPersistStore ? this.globalSetterToPersistStoreAsync : this.globalSetter;
83
- return Object.keys(actions).reduce((accumulator, key) => (Object.assign(Object.assign({}, accumulator), { [key]: (...parameres) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
84
- let promise;
85
- const setterWrapper = (value) => {
86
- promise = setter(value);
87
- return promise;
88
- };
89
- const result = actions[key](...parameres)(setterWrapper, this.getStateCopy());
90
- const resultPromise = Promise.resolve(result) === result ? result : Promise.resolve();
91
- yield Promise.all([promise, resultPromise]);
92
- return result;
93
- }) })), {});
198
+ /**
199
+ * Calculate whenever or not we should compute the callback parameters on the state change
200
+ * @returns {boolean} - True if we should compute the callback parameters on the state change
201
+ * */
202
+ this.hasStateCallbacks = () => {
203
+ const { computePreventStateChange, onStateChanged } = this;
204
+ const { computePreventStateChange: computePreventStateChangeFromConfig, onStateChanged: onStateChangedFromConfig, } = this.config;
205
+ const preventStateChangesCalls = computePreventStateChange || computePreventStateChangeFromConfig;
206
+ const stateChangeCalls = onStateChanged || onStateChangedFromConfig;
207
+ const shouldComputeParameter = preventStateChangesCalls || stateChangeCalls;
208
+ return !!shouldComputeParameter;
94
209
  };
95
- this.deleteAsyncStoreItem = () => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
96
- if (!this.isPersistStore)
97
- return;
98
- yield async_storage_1.default.removeItem(this.persistStoreAs);
99
- });
100
- }
101
- get isPersistStore() {
102
- return !!this.persistStoreAs;
103
- }
104
- get isStoredStateItemUpdated() {
105
- return this.storedStateItem !== undefined;
106
- }
107
- asyncStorageGetItem() {
108
- return async_storage_1.default.getItem(this.persistStoreAs);
109
- }
110
- getAsyncStoreItem() {
111
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
112
- if (this.isStoredStateItemUpdated)
113
- return this.storedStateItem;
114
- if (this.getAsyncStoreItemPromise)
115
- return this.getAsyncStoreItemPromise;
116
- this.getAsyncStoreItemPromise = new Promise((resolve) => {
117
- (() => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
118
- var _a;
119
- const item = yield this.asyncStorageGetItem();
120
- if (item) {
121
- let value = JSON.parse(item);
122
- /** This allow users to review what is been stored */
123
- value = (_a = this.onPersistStorageLoad(value)) !== null && _a !== void 0 ? _a : value;
124
- const newState = (0, json_storage_formatter_1.formatFromStore)(value);
125
- yield this.globalSetter(newState);
126
- }
127
- resolve(this.state);
128
- }))();
210
+ /**
211
+ * This is responsible for defining whenever or not the state change should be allowed or prevented
212
+ * the function also execute the functions:
213
+ * - onStateChanged (if defined) - this function is executed after the state change
214
+ * - computePreventStateChange (if defined) - this function is executed before the state change and it should return a boolean value that will be used to determine if the state change should be prevented or not
215
+ * @param {{ setter: StateSetter<TState>; invokerSetState?: React.Dispatch<React.SetStateAction<TState>> }} parameters - The state setter and the setState function of the component that invoked the state change (optional) (default: null) this is used to updated first the component that invoked the state change
216
+ */
217
+ this.computeSetState = ({ setter, invokerSetState, }) => {
218
+ const isSetterFunction = typeof setter === 'function';
219
+ const previousState = this.getStateClone();
220
+ const newState = isSetterFunction
221
+ ? setter(previousState)
222
+ : setter;
223
+ const itHasStateCallbacks = this.hasStateCallbacks();
224
+ const actions = itHasStateCallbacks && this.getStoreActionsMap({});
225
+ const setState = itHasStateCallbacks && this.getSetStateWrapper({ invokerSetState });
226
+ const { setMetadata, getMetadataClone: getMetadata, getStateClone: getState, } = this;
227
+ const callbackParameter = {
228
+ setMetadata,
229
+ getMetadata,
230
+ setState,
231
+ getState,
232
+ actions,
233
+ previousState,
234
+ state: newState,
235
+ };
236
+ const { computePreventStateChange } = this;
237
+ const { computePreventStateChange: computePreventStateChangeFromConfig } = this.config;
238
+ // check if the state change should be prevented
239
+ if (computePreventStateChange || computePreventStateChangeFromConfig) {
240
+ const preventStateChange = (computePreventStateChange === null || computePreventStateChange === void 0 ? void 0 : computePreventStateChange(callbackParameter)) ||
241
+ (computePreventStateChangeFromConfig === null || computePreventStateChangeFromConfig === void 0 ? void 0 : computePreventStateChangeFromConfig(callbackParameter));
242
+ if (preventStateChange)
243
+ return;
244
+ }
245
+ this.setState({
246
+ invokerSetState,
247
+ state: newState,
129
248
  });
130
- return this.getAsyncStoreItemPromise;
131
- });
132
- }
133
- asyncStorageSetItem(valueToStore) {
134
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
135
- yield async_storage_1.default.setItem(this.persistStoreAs, valueToStore);
136
- });
137
- }
138
- setAsyncStoreItem() {
139
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
140
- if (this.storedStateItem === this.state)
249
+ const { onStateChanged } = this;
250
+ const { onStateChanged: onStateChangedFromConfig } = this.config;
251
+ if (!onStateChanged && !onStateChangedFromConfig)
141
252
  return;
142
- this.storedStateItem = this.state;
143
- const valueToStore = (0, json_storage_formatter_1.formatToStore)(this.state);
144
- yield this.asyncStorageSetItem(JSON.stringify(valueToStore));
145
- });
253
+ onStateChanged === null || onStateChanged === void 0 ? void 0 : onStateChanged(callbackParameter);
254
+ onStateChangedFromConfig === null || onStateChangedFromConfig === void 0 ? void 0 : onStateChangedFromConfig(callbackParameter);
255
+ };
256
+ /**
257
+ * This creates a map of actions that can be used to modify or interact with the state
258
+ * @param {{ invokerSetState?: React.Dispatch<React.SetStateAction<TState>> }} parameters - The setState function of the component that invoked the state change (optional) (default: null) this is used to updated first the component that invoked the state change
259
+ * @returns {ActionCollectionResult<TState, TMetadata, TStateSetter>} - The actions map result of the configuration object passed to the constructor
260
+ * */
261
+ this.getStoreActionsMap = ({ invokerSetState, }) => {
262
+ if (!this.setterConfig)
263
+ return null;
264
+ const { setterConfig, setMetadata } = this;
265
+ const actionsConfig = setterConfig;
266
+ const actionsKeys = Object.keys(actionsConfig);
267
+ const setState = this.getSetStateWrapper({
268
+ invokerSetState,
269
+ });
270
+ // we expose a copy of the state and metadata to the actions to prevent them from modifying the state directly
271
+ const { getStateClone: getState, getMetadataClone: getMetadata } = this;
272
+ // we bind the functions to the actions object to allow reusing actions in the same api config by using the -this- keyword
273
+ const actions = actionsKeys.reduce((accumulator, action_key) => (Object.assign(Object.assign({}, accumulator), { [action_key](...parameres) {
274
+ const actionConfig = actionsConfig[action_key];
275
+ const action = actionConfig.apply(actions, parameres);
276
+ const actionIsNotAFunction = typeof action !== 'function';
277
+ // we throw an error if the action is not a function, this is mandatory for the correct execution of the actions
278
+ if (actionIsNotAFunction) {
279
+ throwWrongKeyOnActionCollectionConfig(action_key);
280
+ }
281
+ // executes the actions bringing access to the state setter and a copy of the state
282
+ const result = action.call(actions, {
283
+ setState,
284
+ getState,
285
+ setMetadata,
286
+ getMetadata,
287
+ });
288
+ // we return the result of the actions to the invoker
289
+ return result;
290
+ } })), {});
291
+ return actions;
292
+ };
293
+ this.onInitializeStore();
146
294
  }
147
- get stateOrchestrator() {
148
- if (this._stateOrchestrator)
149
- return this._stateOrchestrator;
150
- if (this.actions) {
151
- this._stateOrchestrator = this.getActions();
152
- }
153
- else if (this.persistStoreAs) {
154
- this._stateOrchestrator = this.globalSetterToPersistStoreAsync;
155
- }
156
- else {
157
- this._stateOrchestrator = this.globalSetter;
295
+ /**
296
+ * Returns the state setter or the actions map
297
+ * @param {{ invokerSetState?: React.Dispatch<React.SetStateAction<TState>> }} parameters - The setState function of the component that invoked the state change (optional) (default: null) this is used to updated first the component that invoked the state change
298
+ * @returns {TStateSetter} - The state setter or the actions map
299
+ * */
300
+ getStateOrchestrator(invokerSetState) {
301
+ const stateHasCustomActions = this.setterConfig;
302
+ if (stateHasCustomActions) {
303
+ return this.getStoreActionsMap({ invokerSetState });
158
304
  }
159
- return this._stateOrchestrator;
305
+ return this.getSetStateWrapper({ invokerSetState });
160
306
  }
161
307
  }
162
308
  exports.GlobalStore = GlobalStore;
163
- /**
164
- ** [subscriber-update-callback, hook]
165
- */
166
- GlobalStore.batchedUpdates = [];
167
- /**
168
- * React native cannot use unstable_batchedUpdates
169
- */
170
- GlobalStore.ExecutePendingBatches = () => {
171
- GlobalStore.batchedUpdates.forEach(([execute]) => {
172
- execute();
173
- });
174
- GlobalStore.batchedUpdates = [];
175
- };
176
309
  exports.default = GlobalStore;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @param {StateSetter<TState>} setter - add a new state to an existing state
3
+ * @returns {void} result - void
4
+ */
5
+ export type StateSetter<TState> = (setter: TState | ((state: TState) => TState)) => void;
6
+ /**
7
+ * Parameters of the onStateChanged callback function
8
+ * @param {TState} state - the new state
9
+ * @param {TState} previousState - the previous state
10
+ **/
11
+ export type StateChanges<TState> = {
12
+ state: TState;
13
+ previousState?: TState;
14
+ };
15
+ /**
16
+ * Callbacks to be passed to the configurating function of the store
17
+ * @template {TState} TState - The state type
18
+ * @template {TMetadata} TMetadata - The metadata type
19
+ * @property {StateSetter<TState>} setMetadata - Set the metadata
20
+ * @property {StateSetter<TState>} setState - Set the state
21
+ * @property {() => TState} getState - Get the state
22
+ * @property {() => TMetadata} getMetadata - Get the metadata
23
+ **/
24
+ export type StoreTools<TState, TMetadata = null> = {
25
+ setMetadata: StateSetter<TMetadata>;
26
+ setState: StateSetter<TState>;
27
+ getState: () => TState;
28
+ getMetadata: () => TMetadata;
29
+ };
30
+ /**
31
+ * Basic contract for the storeActionsConfig configuration
32
+ * @template {TState} TState - The state type
33
+ * @template {TMetadata} TMetadata - The metadata type
34
+ * @property {string} key - The action name
35
+ * @property {(...parameters: unknown[]) => (storeTools: { setMetadata: StateSetter<TMetadata>; setState: StateSetter<TState>; getState: () => TState; getMetadata: () => TMetadata; }) => unknown | void} value - The action function
36
+ * @returns {ActionCollectionConfig<TState, TMetadata>} result - The action collection configuration
37
+ */
38
+ export interface ActionCollectionConfig<TState, TMetadata> {
39
+ [key: string]: (...parameters: any[]) => (storeTools: StoreTools<TState, TMetadata>) => unknown | void;
40
+ }
41
+ /**
42
+ * This is the actions object returned by the hook when you pass an storeActionsConfig configuration
43
+ * if you pass an storeActionsConfig configuration, the hook will return an object with the actions
44
+ * whatever data manipulation of the state should be executed through the custom actions with as access to the state and metadata
45
+ * @template {TState} TState - The state type
46
+ * @template {TMetadata} TMetadata - The metadata type
47
+ * @template {TStateSetter} TStateSetter - The storeActionsConfig type (optional) - if you pass an storeActionsConfig the hook will return an object with the actions
48
+ *
49
+ * @example
50
+ *
51
+ * const store = new GlobalStore(0, {
52
+ * increment: () => ({ setState }) => {
53
+ * setState((state) => state + 1);
54
+ * },
55
+ * decrement: () => ({ setState }) => {
56
+ * setState((state) => state - 1);
57
+ * },
58
+ * });
59
+ *
60
+ * const [state, actions] = store.getHook();
61
+ *
62
+ * actions.increment();
63
+ * actions.decrement();
64
+ *
65
+ * console.log(state); // 0
66
+ */
67
+ export type ActionCollectionResult<TState, TMetadata, TStateSetter extends ActionCollectionConfig<TState, TMetadata> | StateSetter<TState> = StateSetter<TState>> = TStateSetter extends ActionCollectionConfig<TState, TMetadata> ? {
68
+ [key in keyof TStateSetter]: (...params: Parameters<TStateSetter[key]>) => ReturnType<ReturnType<TStateSetter[key]>>;
69
+ } : null;
70
+ /**
71
+ * Common parameters of the store configuration callback functions
72
+ * @param {StateSetter<TState>} setState - add a new value to the state
73
+ * @param {() => TState} getState - get the current state
74
+ * @param {StateSetter<TMetadata>} setMetadata - add a new value to the metadata
75
+ * @param {() => TMetadata} getMetadata - get the current metadata
76
+ * @param {ActionCollectionResult<TState, ActionCollectionConfig<TState, TMetadata>> | null} actions - the actions object returned by the hook when you pass an storeActionsConfig configuration otherwise null
77
+ * @template {TState} TState - The state type
78
+ * @template {TMetadata} TMetadata - The metadata type
79
+ * @template {TStateSetter} TStateSetter - The storeActionsConfig type (optional) - if you pass an storeActionsConfig the hook will return an object with the actions
80
+ * @template {ActionCollectionResult<TState, TStateSetter>} TStateSetter - the result of the API (optional) - if you don't pass an API as a parameter, you can pass null
81
+ * */
82
+ export type StateConfigCallbackParam<TState, TMetadata, TStateSetter extends ActionCollectionConfig<TState, TMetadata> | StateSetter<TState> = StateSetter<TState>> = {
83
+ actions: TStateSetter extends ActionCollectionConfig<TState, TMetadata> ? ActionCollectionResult<TState, TMetadata, TStateSetter> : null;
84
+ } & StoreTools<TState, TMetadata>;
85
+ /**
86
+ * Parameters of the onStateChanged callback function
87
+ * @template {TState} TState - The state type
88
+ * @template {TMetadata} TMetadata - The metadata type
89
+ * @template {TStateSetter} TStateSetter - The storeActionsConfig type (optional) - if you pass an storeActionsConfig the hook will return an object with the actions
90
+ */
91
+ export type StateChangesParam<TState, TMetadata, TStateSetter extends ActionCollectionConfig<TState, TMetadata> | StateSetter<TState> = StateSetter<TState>> = StateConfigCallbackParam<TState, TMetadata, TStateSetter> & StateChanges<TState>;
92
+ /**
93
+ * Configuration of the store (optional) - if you don't need to use the store configuration you don't need to pass this parameter
94
+ * @param {StateConfigCallbackParam<TState, TMetadata> => void} onInit - callback function called when the store is initialized
95
+ * @param {StateConfigCallbackParam<TState, TMetadata> => void} onSubscribed - callback function called every time a component is subscribed to the store
96
+ * @param {StateChangesParam<TState, TMetadata> => boolean} computePreventStateChange - callback function called every time the state is changed and it allows you to prevent the state change
97
+ * @param {StateChangesParam<TState, TMetadata> => void} onStateChanged - callback function called every time the state is changed
98
+ * @template TState - the type of the state
99
+ * @template TMetadata - the type of the metadata (optional) - if you don't pass an metadata as a parameter, you can pass null
100
+ * @template {ActionCollectionConfig<TState,TMetadata> | null} TStateSetter - the configuration of the API (optional) - if you don't pass an API as a parameter, you can pass null
101
+ * */
102
+ export type GlobalStoreConfig<TState, TMetadata, TStateSetter extends ActionCollectionConfig<TState, TMetadata> | StateSetter<TState> = StateSetter<TState>> = {
103
+ onInit?: (parameters: StateConfigCallbackParam<TState, TMetadata, TStateSetter>) => void;
104
+ onStateChanged?: (parameters: StateChangesParam<TState, TMetadata, TStateSetter>) => void;
105
+ onSubscribed?: (parameters: StateConfigCallbackParam<TState, TMetadata, TStateSetter>) => void;
106
+ computePreventStateChange?: (parameters: StateChangesParam<TState, TMetadata, TStateSetter>) => boolean;
107
+ };
108
+ //# sourceMappingURL=GlobalStore.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GlobalStore.types.d.ts","sourceRoot":"","sources":["../src/GlobalStore.types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { formatToStore, formatFromStore, clone } from 'json-storage-formatter';
2
+ export { formatToStore, formatFromStore, clone };
3
+ /**
4
+ * Debounce function to prevent multiple calls to the same function in a short period of time
5
+ * @param callback Function to be called
6
+ * @param wait Time to wait before calling the function
7
+ * @returns Function to be called
8
+ */
9
+ export declare const debounce: <T extends Function>(callback: T, wait?: number) => T;
10
+ //# sourceMappingURL=GlobalStore.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GlobalStore.utils.d.ts","sourceRoot":"","sources":["../src/GlobalStore.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAG/E,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,uDAUpB,CAAC"}