react-native-global-state-hooks 3.0.5 → 3.0.7

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.
package/README.md CHANGED
@@ -17,22 +17,26 @@ For seen a running example of the hooks, you can check the following link: [reac
17
17
  We are gonna create a global count example **useCountGlobal.ts**:
18
18
 
19
19
  ```ts
20
- import { GlobalStore } from 'react-native-global-state-hooks';
20
+ import { createGlobalHook } from 'react-native-global-state-hooks';
21
21
 
22
22
  // initialize your store with the default value of the same.
23
- const countStore = new GlobalStore(0);
24
-
25
- // get the hook
26
- export const useCountGlobal = countStore.getHook();
23
+ export const useCountGlobal = createGlobalHook(0);
27
24
 
28
25
  // inside your component just call...
29
- const [count, setCount] = useCountGlobal(); // no paremeters are needed since this is a global store
26
+ const [count, setCount] = useCountGlobal(); // no parameters are needed since this is a global store
30
27
 
31
28
  // That's it, that's a global store... Strongly typed, with a global-hook that we could reuse cross all our react-components.
32
29
 
33
30
  // #### Optionally you are able to use a decoupled hook,
34
31
  // #### This function is linked to the store hooks but is not a hook himself.
35
32
 
33
+ // we could create the store in this way to get extra capabilities
34
+ const countStore = new GlobalStore(0);
35
+
36
+ // the useCountGlobal works exactly the same
37
+ export const useCountGlobal = countStore.getHook();
38
+
39
+ // but now we are also able to get a decoupled hook
36
40
  export const [getCount, sendCount] = countStore.getHookDecoupled();
37
41
 
38
42
  // @example
@@ -109,14 +113,14 @@ Let's see a trivial example:
109
113
  ```JSX
110
114
  import { useCountGlobal, sendCount } from './useCountGlobal'
111
115
 
112
- const CountDisplayerComponent: React.FC = () => {
116
+ const CountDisplayComponent: React.FC = () => {
113
117
  const [count] = useCountGlobal();
114
118
 
115
119
  return (<Text>{count}<Text/>);
116
120
  }
117
121
 
118
122
  // here we have a separate component that is gonna handle the state of the previous component we created,
119
- // this new component is not gonna be affected by the changes applied on <CountDisplayerComponent/>
123
+ // this new component is not gonna be affected by the changes applied on <CountDisplayComponent/>
120
124
  // Stage2 does not need to be updated once the global count changes
121
125
  const CountManagerComponent: React.FC = () => {
122
126
  const increaseClick = useCallback(() => sendCount(count => count + 1), []);
@@ -137,13 +141,13 @@ const CountManagerComponent: React.FC = () => {
137
141
 
138
142
  Implementing extra functionality to extend the capabilities of the GlobalStorage couldn't be easier!!!
139
143
 
140
- Here is an example of how you could create your custom store that for example stores the state into a async-storage persistente...
144
+ Here is an example of how you could create your custom store that for example stores the state into a async-storage persistent...
141
145
 
142
146
  You could just use this code right as it is by just adding also into your project **@react-native-async-storage** or whatever another async storage library.
143
147
 
144
148
  ```ts
145
149
  import asyncStorage from '@react-native-async-storage/async-storage';
146
- import { clone, formatFromStore, formatToStore } from 'json-storage-formatter';
150
+ import { formatFromStore, formatToStore } from 'json-storage-formatter';
147
151
 
148
152
  import {
149
153
  GlobalStore as GlobalStoreBase,
@@ -153,120 +157,67 @@ import {
153
157
  StateSetter,
154
158
  } from 'react-native-global-state-hooks';
155
159
 
156
- /**
157
- * GlobalStore is an store that could also persist the state in the async storage
158
- * @template {TState} TState - The state of the store
159
- * @template {TMetadata} TMetadata - The metadata of the store, it must contain a readonly property called isAsyncStorageReady which cannot be set from outside the store
160
- * @template {TStateSetter} TStateSetter - The storeActionsConfig of the store
161
- */
162
160
  export class GlobalStore<
163
161
  TState,
164
- // this restriction is needed to avoid the consumers to set the isAsyncStorageReady property from outside the store,
165
- // ... even when the value will be ignored is better to avoid it to avoid confusion
166
- TMetadata extends { readonly isAsyncStorageReady?: never } & Record<
167
- string,
168
- unknown
169
- > = {},
170
- TStateSetter extends StorageSetter<TState, TMetadata> = StateSetter<TState>
171
- > extends GlobalStoreBase<TState, StorageMetadata<TMetadata>, TStateSetter> {
172
- /**
173
- * Config for the async storage
174
- * includes the asyncStorageKey and the metadata which will be used to determine if the async storage is ready or not
175
- * @template {TState} TState - The state of the store
176
- * @template {TMetadata} TMetadata - The metadata of the store
177
- * @template {TStateSetter} TStateSetter - The storeActionsConfig of the store
178
- **/
179
- protected config: StorageConfig<TState, TMetadata, TStateSetter> = {};
180
-
181
- /**
182
- * Creates a new instance of the GlobalStore
183
- * @param {TState} state - The initial state of the store
184
- * @param {GlobalStoreConfig<TState, TMetadata, ActionCollectionConfig<TState, TMetadata> | StateSetter<TState>> & { asyncStorageKey: string; }} config - The config of the store
185
- * @param {GlobalStoreConfig<TState, TMetadata, ActionCollectionConfig<TState, TMetadata> | StateSetter<TState>> & { asyncStorageKey: string; }} config.metadata - The metadata of the store which will be used to determine if the async storage is ready or not, also it could store no reactive data
186
- * @param {GlobalStoreConfig<TState, TMetadata, ActionCollectionConfig<TState, TMetadata> | StateSetter<TState>> & { asyncStorageKey: string; }} config.asyncStorageKey - The key of the async storage
187
- * @param {GlobalStoreConfig<TState, TMetadata, ActionCollectionConfig<TState, TMetadata> | StateSetter<TState>> & { asyncStorageKey: string; }} config.onInit - The callback that will be called once the store is created
188
- * @param {GlobalStoreConfig<TState, TMetadata, ActionCollectionConfig<TState, TMetadata> | StateSetter<TState>> & { asyncStorageKey: string; }} config.onStateChange - The callback that will be called once the state is changed
189
- * @param {GlobalStoreConfig<TState, TMetadata, ActionCollectionConfig<TState, TMetadata> | StateSetter<TState>> & { asyncStorageKey: string; }} config.onSubscribed - The callback that will be called every time a new component is subscribed to the store
190
- * @param {GlobalStoreConfig<TState, TMetadata, ActionCollectionConfig<TState, TMetadata> | StateSetter<TState>> & { asyncStorageKey: string; }} config.computePreventStateChange - The callback that will be called before the state is changed, if it returns true the state will not be changed
191
- * @param {TStateSetter} setterConfig - The actions configuration object (optional) (default: null) if not null the store manipulation will be done through the actions
192
- */
162
+ TMetadata extends {
163
+ asyncStorageKey?: string;
164
+ isAsyncStorageReady?: boolean;
165
+ },
166
+ TStateSetter extends
167
+ | ActionCollectionConfig<TState, TMetadata>
168
+ | StateSetter<TState> = StateSetter<TState>
169
+ > extends GlobalStoreAbstract<TState, TMetadata, TStateSetter> {
193
170
  constructor(
194
171
  state: TState,
195
- config: StorageConfig<TState, TMetadata, TStateSetter> | null = null,
172
+ config: GlobalStoreConfig<TState, TMetadata, TStateSetter> = {},
196
173
  setterConfig: TStateSetter | null = null
197
174
  ) {
198
- const { onInit, asyncStorageKey, ...configParameters } =
199
- config ?? ({} as StorageConfig<TState, TMetadata, TStateSetter>);
200
-
201
- super(state, configParameters, setterConfig as TStateSetter);
202
-
203
- // if there is not async storage key this is not a persistent store
204
- const isAsyncStorageReady: boolean | null = asyncStorageKey ? false : null;
205
-
206
- this.config = {
207
- ...config,
208
- metadata: {
209
- ...((configParameters.metadata ?? {}) as TMetadata),
210
- isAsyncStorageReady,
211
- },
212
- };
213
-
214
- const hasInitCallbacks = !!(asyncStorageKey || onInit);
215
- if (!hasInitCallbacks) return;
175
+ super(state, config, setterConfig);
216
176
 
217
- const parameters = this.getConfigCallbackParam({});
218
-
219
- this.onInit(parameters);
220
- onInit?.(parameters);
177
+ this.initialize();
221
178
  }
222
179
 
223
- /**
224
- * This method will be called once the store is created after the constructor,
225
- * this method is different from the onInit of the config property and it won't be overridden
226
- */
227
- protected onInit = async ({
180
+ protected onInitialize = async ({
228
181
  setState,
229
182
  setMetadata,
230
183
  getMetadata,
231
- }: StateConfigCallbackParam<
232
- TState,
233
- StorageMetadata<TMetadata>,
234
- NonNullable<TStateSetter>
235
- >) => {
236
- const { asyncStorageKey } = this.config;
184
+ getState,
185
+ }: StateConfigCallbackParam<TState, TMetadata, TStateSetter>) => {
186
+ const metadata = getMetadata();
187
+ const { asyncStorageKey } = metadata;
188
+
237
189
  if (!asyncStorageKey) return;
238
190
 
239
191
  const storedItem = (await asyncStorage.getItem(asyncStorageKey)) as string;
240
-
241
192
  setMetadata({
242
- ...getMetadata(),
193
+ ...metadata,
243
194
  isAsyncStorageReady: true,
244
195
  });
245
196
 
246
197
  if (storedItem === null) {
247
- const state = clone(this.state);
198
+ const state = getState();
248
199
 
249
- // this forces the react to re-render the component when the state is an object
250
- return setState(state);
200
+ // force the re-render of the subscribed components even if the state is the same
201
+ return setState(state, { forceUpdate: true });
251
202
  }
252
203
 
253
- const jsonParsed = JSON.parse(storedItem);
254
- const items = formatFromStore<TState>(jsonParsed);
204
+ const items = formatFromStore<TState>(storedItem, {
205
+ jsonParse: true,
206
+ });
255
207
 
256
- setState(items);
208
+ setState(items, { forceUpdate: true });
257
209
  };
258
210
 
259
- protected onStateChanged = ({
211
+ protected onChange = ({
212
+ getMetadata,
260
213
  getState,
261
- }: StateChangesParam<
262
- TState,
263
- StorageMetadata<TMetadata>,
264
- NonNullable<TStateSetter>
265
- >) => {
266
- const { asyncStorageKey } = this.config;
214
+ }: StateChangesParam<TState, TMetadata, NonNullable<TStateSetter>>) => {
215
+ const { asyncStorageKey } = getMetadata();
216
+
267
217
  if (!asyncStorageKey) return;
268
218
 
269
219
  const state = getState();
220
+
270
221
  const formattedObject = formatToStore(state, {
271
222
  stringify: true,
272
223
  });
@@ -274,76 +225,6 @@ export class GlobalStore<
274
225
  asyncStorage.setItem(asyncStorageKey, formattedObject);
275
226
  };
276
227
  }
277
-
278
- /**
279
- * Metadata of the store
280
- * @template {TMetadata} TMetadata - The metadata type which also contains the isAsyncStorageReady property
281
- */
282
- type StorageMetadata<TMetadata> = Omit<TMetadata, 'isAsyncStorageReady'> & {
283
- readonly isAsyncStorageReady?: boolean | null;
284
- };
285
-
286
- /**
287
- * The setter of the store
288
- * @template {TState} TState - The state of the store
289
- * @template {TMetadata} TMetadata - The metadata of the store, it must contain a readonly property called isAsyncStorageReady which cannot be set from outside the store
290
- * */
291
- type StorageSetter<TState, TMetadata> =
292
- | ActionCollectionConfig<TState, StorageMetadata<TMetadata>>
293
- | StateSetter<TState>
294
- | null;
295
-
296
- /**
297
- * Config for the async storage
298
- * includes the asyncStorageKey
299
- * @template {TState} TState - The state of the store
300
- * @template {TMetadata} TMetadata - The metadata of the store, it must contain a readonly property called isAsyncStorageReady which cannot be set from outside the store
301
- * @template {TStateSetter} TStateSetter - The storeActionsConfig of the store
302
- */
303
- type StorageConfig<
304
- TState,
305
- TMetadata extends { readonly isAsyncStorageReady?: never },
306
- TStateSetter extends
307
- | ActionCollectionConfig<TState, StorageMetadata<TMetadata>>
308
- | StateSetter<TState>
309
- | null = StateSetter<TState>
310
- > = {
311
- asyncStorageKey?: string;
312
-
313
- metadata?: TMetadata;
314
-
315
- onInit?: (
316
- parameters: StateConfigCallbackParam<
317
- TState,
318
- StorageMetadata<TMetadata>,
319
- NonNullable<TStateSetter>
320
- >
321
- ) => void;
322
-
323
- onStateChanged?: (
324
- parameters: StateChangesParam<
325
- TState,
326
- StorageMetadata<TMetadata>,
327
- NonNullable<TStateSetter>
328
- >
329
- ) => void;
330
-
331
- onSubscribed?: (
332
- parameters: StateConfigCallbackParam<
333
- TState,
334
- StorageMetadata<TMetadata>,
335
- NonNullable<TStateSetter>
336
- >
337
- ) => void;
338
-
339
- computePreventStateChange?: (
340
- parameters: StateChangesParam<
341
- TState,
342
- StorageMetadata<TMetadata>,
343
- NonNullable<TStateSetter>
344
- >
345
- ) => boolean;
346
- };
347
228
  ```
348
229
 
349
230
  The methods **formatToStore** and **formatFromStore** are part of another library of my [json-storage-formatter](https://www.npmjs.com/package/json-storage-formatter)...
@@ -362,7 +243,7 @@ const [count, setCount, { isAsyncStorageReady }] = useCountGlobal();
362
243
 
363
244
  Originally the library was implementing persistent storage by using the package **@react-native-async-storage**, but not all people want to use it or need to use it... so it has been removed. Feel free to use the above example to get back that functionality if you were using the previous versions of the package.
364
245
 
365
- You could find this example on the [**GitHub** of the project](https://github.com/johnny-quesada-developer/json-storage-formatter), between the unit test sources when the case scenario was tested [GlobalStoreAsyc.ts](https://github.com/johnny-quesada-developer/react-native-global-state-hooks/blob/master/%40tests/__test__/GlobalStoreAsyc.ts)
246
+ You could find this example on the [**GitHub** of the project](https://github.com/johnny-quesada-developer/json-storage-formatter), between the unit test sources when the case scenario was tested [GlobalStoreAsync.ts](https://github.com/johnny-quesada-developer/react-native-global-state-hooks/blob/master/%40tests/__test__/GlobalStoreAsyc.ts)
366
247
 
367
248
  ...
368
249
 
@@ -380,7 +261,7 @@ const initialValue = 0;
380
261
 
381
262
  const config = {
382
263
  // this is not reactive information that you could also store in the async storage
383
- // upating the metadata will not trigger the onStateChanged method or any update on the components
264
+ // updating the metadata will not trigger the onStateChanged method or any update on the components
384
265
  metadata: null,
385
266
 
386
267
  // The lifecycle callbacks are: onInit, onStateChanged, onSubscribed and computePreventStateChange
@@ -756,7 +637,7 @@ const App = () => {
756
637
  return (
757
638
  <UserProvider>
758
639
  <CountProvider>
759
- {/* lets create two componets instead of one */}
640
+ {/* lets create two components instead of one */}
760
641
  <ComponentSetter />
761
642
  <Component />
762
643
  </CountProvider>
@@ -895,14 +776,14 @@ There is also a third element in the tuple which is a function for getting the m
895
776
  ```tsx
896
777
  const [, , getMetadata] = new GlobalStore(0, {
897
778
  metadata: {
898
- isStoredSyncronized: false,
779
+ isStoredSynchronized: false,
899
780
  },
900
781
  }).getHookDecoupled();
901
782
 
902
- console.log(getMetadata().isStoredSyncronized); // false
783
+ console.log(getMetadata().isStoredSynchronized); // false
903
784
  ```
904
785
 
905
- The setMetadata is part of the store tools, so it can be used in the actions, but againg the metadata is not reactive!! so it will not trigger a re-render on the subscribers
786
+ The setMetadata is part of the store tools, so it can be used in the actions, but again the metadata is not reactive!! so it will not trigger a re-render on the subscribers
906
787
 
907
788
  ...
908
789
 
@@ -1,5 +1,5 @@
1
1
  import { Dispatch, SetStateAction } from 'react';
2
- import { ActionCollectionConfig, StateSetter, GlobalStoreConfig, ActionCollectionResult, StateConfigCallbackParam } from './GlobalStore.types';
2
+ import { ActionCollectionConfig, StateSetter, GlobalStoreConfig, ActionCollectionResult, StateConfigCallbackParam, StateChangesParam } from './GlobalStore.types';
3
3
  /**
4
4
  * The GlobalStore class is the main class of the library and it is used to create a GlobalStore instances
5
5
  * @template {TState} TState - The type of the state object
@@ -7,13 +7,14 @@ import { ActionCollectionConfig, StateSetter, GlobalStoreConfig, ActionCollectio
7
7
  * @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
8
8
  * */
9
9
  export declare class GlobalStore<TState, TMetadata = null, TStateSetter extends ActionCollectionConfig<TState, TMetadata> | StateSetter<TState> | null = StateSetter<TState>> {
10
- protected state: TState;
11
10
  protected setterConfig: TStateSetter | null;
12
11
  /**
13
12
  * list of all the subscribers setState functions
14
13
  * @template {TState} TState - The type of the state object
15
14
  * */
16
- subscribers: Set<StateSetter<TState>>;
15
+ subscribers: Set<StateSetter<{
16
+ state: TState;
17
+ }>>;
17
18
  /**
18
19
  * additional configuration for the store
19
20
  * @template {TState} TState - The type of the state object
@@ -75,6 +76,16 @@ export declare class GlobalStore<TState, TMetadata = null, TStateSetter extends
75
76
  * @returns {boolean} - true to prevent the state change, false to allow the state change
76
77
  * */
77
78
  protected computePreventStateChange?: GlobalStoreConfig<TState, TMetadata, TStateSetter>['computePreventStateChange'];
79
+ /**
80
+ * We use a wrapper in order to be able to force the state update when necessary even with primitive types
81
+ */
82
+ protected stateWrapper: {
83
+ state: TState;
84
+ };
85
+ /**
86
+ * @deprecated direct modifications of the state could end up in unexpected behaviors
87
+ */
88
+ protected get state(): TState;
78
89
  /**
79
90
  * Create a simple global store
80
91
  * @param {TState} state - The initial state
@@ -104,17 +115,7 @@ export declare class GlobalStore<TState, TMetadata = null, TStateSetter extends
104
115
  * @param {TStateSetter} setterConfig - The actions configuration object (optional) (default: null) if not null the store manipulation will be done through the actions
105
116
  * */
106
117
  constructor(state: TState, config: GlobalStoreConfig<TState, TMetadata, TStateSetter>, setterConfig: TStateSetter);
107
- protected onInitializeStore: () => void;
108
- /**
109
- * gets a clone of the state
110
- * @returns {TState} - The state clone
111
- * */
112
- protected getStateClone: () => TState;
113
- /**
114
- * gets a clone of the metadata
115
- * @returns {TMetadata} - The metadata clone
116
- * */
117
- protected getMetadataClone: () => TMetadata;
118
+ protected initialize: () => void;
118
119
  /**
119
120
  * set the state and update all the subscribers
120
121
  * @param {StateSetter<TState>} setter - The setter function or the value to set
@@ -122,7 +123,9 @@ export declare class GlobalStore<TState, TMetadata = null, TStateSetter extends
122
123
  * */
123
124
  protected setState: ({ invokerSetState, state, }: {
124
125
  state: TState;
125
- invokerSetState?: React.Dispatch<React.SetStateAction<TState>>;
126
+ invokerSetState?: Dispatch<SetStateAction<{
127
+ state: TState;
128
+ }>>;
126
129
  }) => void;
127
130
  /**
128
131
  * Set the value of the metadata property, this is no reactive and will not trigger a re-render
@@ -137,7 +140,9 @@ export declare class GlobalStore<TState, TMetadata = null, TStateSetter extends
137
140
  * @returns {StateConfigCallbackParam<TState, TMetadata>} - The parameters object
138
141
  * */
139
142
  protected getConfigCallbackParam: ({ invokerSetState, }: {
140
- invokerSetState?: React.Dispatch<React.SetStateAction<TState>>;
143
+ invokerSetState?: React.Dispatch<React.SetStateAction<{
144
+ state: TState;
145
+ }>>;
141
146
  }) => StateConfigCallbackParam<TState, TMetadata, TStateSetter>;
142
147
  /**
143
148
  * Returns a custom hook that allows to handle a global state
@@ -155,14 +160,18 @@ export declare class GlobalStore<TState, TMetadata = null, TStateSetter extends
155
160
  * @returns {StateSetter<TState>} - The state setter
156
161
  * */
157
162
  protected getSetStateWrapper: ({ invokerSetState, }?: {
158
- invokerSetState?: React.Dispatch<React.SetStateAction<TState>>;
163
+ invokerSetState?: React.Dispatch<React.SetStateAction<{
164
+ state: TState;
165
+ }>>;
159
166
  }) => StateSetter<TState>;
160
167
  /**
161
168
  * Returns the state setter or the actions map
162
169
  * @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
163
170
  * @returns {TStateSetter} - The state setter or the actions map
164
171
  * */
165
- protected getStateOrchestrator(invokerSetState?: React.Dispatch<React.SetStateAction<TState>>): StateSetter<TState> | ActionCollectionResult<TState, TMetadata, TStateSetter>;
172
+ protected getStateOrchestrator(invokerSetState?: React.Dispatch<React.SetStateAction<{
173
+ state: TState;
174
+ }>>): StateSetter<TState> | ActionCollectionResult<TState, TMetadata, TStateSetter>;
166
175
  /**
167
176
  * Calculate whenever or not we should compute the callback parameters on the state change
168
177
  * @returns {boolean} - True if we should compute the callback parameters on the state change
@@ -175,16 +184,35 @@ export declare class GlobalStore<TState, TMetadata = null, TStateSetter extends
175
184
  * - 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
176
185
  * @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
177
186
  */
178
- protected computeSetState: ({ setter, invokerSetState, }: {
187
+ protected computeSetState: ({ setter, invokerSetState, forceUpdate, }: {
179
188
  setter: StateSetter<TState>;
180
- invokerSetState?: React.Dispatch<React.SetStateAction<TState>>;
189
+ invokerSetState?: React.Dispatch<React.SetStateAction<{
190
+ state: TState;
191
+ }>>;
192
+ forceUpdate: boolean;
181
193
  }) => void;
182
194
  /**
183
195
  * This creates a map of actions that can be used to modify or interact with the state
184
196
  * @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
185
197
  * @returns {ActionCollectionResult<TState, TMetadata, TStateSetter>} - The actions map result of the configuration object passed to the constructor
186
198
  * */
187
- protected getStoreActionsMap: ({ invokerSetState, }: {
188
- invokerSetState?: React.Dispatch<React.SetStateAction<TState>>;
199
+ protected getStoreActionsMap: ({ invokerSetState, }?: {
200
+ invokerSetState?: React.Dispatch<React.SetStateAction<{
201
+ state: TState;
202
+ }>>;
189
203
  }) => ActionCollectionResult<TState, TMetadata, TStateSetter>;
190
204
  }
205
+ /**
206
+ * Creates a global hook that can be used to access the state and actions across the application
207
+ * @param {TState} state - The initial state of the store
208
+ * @param {GlobalStoreConfig<TState, TMetadata, TStateSetter>} config - The configuration object of the store
209
+ * @param {TStateSetter | null} setterConfig - The configuration object of the state setter (optional) (default: null)
210
+ * @returns {GlobalStoreHook<TState, TMetadata, TStateSetter>} - The hook that can be used to access the state and actions across the application
211
+ */
212
+ export declare const createGlobalHook: <TState, TMetadata = null, TStateSetter extends ActionCollectionConfig<TState, TMetadata> | StateSetter<TState> = StateSetter<TState>>(state: TState, config?: {
213
+ metadata?: TMetadata;
214
+ onInit?: (parameters: StateConfigCallbackParam<TState, TMetadata, TStateSetter>) => void;
215
+ onStateChanged?: (parameters: StateChangesParam<TState, TMetadata, TStateSetter>) => void;
216
+ onSubscribed?: (parameters: StateConfigCallbackParam<TState, TMetadata, TStateSetter>) => void;
217
+ computePreventStateChange?: (parameters: StateChangesParam<TState, TMetadata, TStateSetter>) => boolean;
218
+ }, setterConfig?: TStateSetter) => () => [TState, TStateSetter extends StateSetter<TState> ? StateSetter<TState> : ActionCollectionResult<TState, TMetadata, TStateSetter>, TMetadata];
@@ -2,7 +2,18 @@
2
2
  * @param {StateSetter<TState>} setter - add a new state to an existing state
3
3
  * @returns {void} result - void
4
4
  */
5
- export type StateSetter<TState> = (setter: TState | ((state: TState) => TState)) => void;
5
+ export type StateSetter<TState> = (setter: TState | ((state: TState) => TState),
6
+ /**
7
+ * This parameter indicate whether we should force the re-render of the subscribers even if the state is the same,
8
+ * Do
9
+ */
10
+ { forceUpdate, }?: {
11
+ /**
12
+ * @deprecated forceUpdate normally should not be used inside components
13
+ * Use this flag just in custom implementations of the global store
14
+ */
15
+ forceUpdate?: boolean;
16
+ }) => void;
6
17
  /**
7
18
  * Parameters of the onStateChanged callback function
8
19
  * @param {TState} state - the new state
@@ -13,19 +24,21 @@ export type StateChanges<TState> = {
13
24
  previousState?: TState;
14
25
  };
15
26
  /**
16
- * Callbacks to be passed to the configurating function of the store
27
+ * Callbacks to be passed to the configurations function of the store
17
28
  * @template {TState} TState - The state type
18
29
  * @template {TMetadata} TMetadata - The metadata type
19
30
  * @property {StateSetter<TState>} setMetadata - Set the metadata
20
31
  * @property {StateSetter<TState>} setState - Set the state
21
32
  * @property {() => TState} getState - Get the state
22
33
  * @property {() => TMetadata} getMetadata - Get the metadata
34
+ * @property {ActionCollectionResult<TState, TMetadata>} actions - The actions collection if any
23
35
  **/
24
36
  export type StoreTools<TState, TMetadata = null> = {
25
37
  setMetadata: StateSetter<TMetadata>;
26
38
  setState: StateSetter<TState>;
27
39
  getState: () => TState;
28
40
  getMetadata: () => TMetadata;
41
+ actions: ActionCollectionResult<TState, TMetadata>;
29
42
  };
30
43
  /**
31
44
  * Basic contract for the storeActionsConfig configuration
@@ -0,0 +1,15 @@
1
+ import { StateSetter, StateConfigCallbackParam, StateChangesParam, ActionCollectionConfig, GlobalStoreConfig } from 'GlobalStore.types';
2
+ import { GlobalStore } from './GlobalStore';
3
+ /**
4
+ * @description
5
+ * Use this class to extends the capabilities of the GlobalStore.
6
+ * by implementing the abstract methods onInitialize and onChange.
7
+ * You can use this class to create a store with async storage.
8
+ */
9
+ export declare abstract class GlobalStoreAbstract<TState, TMetadata = null, TStateSetter extends ActionCollectionConfig<TState, TMetadata> | StateSetter<TState> | null = StateSetter<TState>> extends GlobalStore<TState, TMetadata, TStateSetter> {
10
+ constructor(state: TState, config?: GlobalStoreConfig<TState, TMetadata, TStateSetter>, setterConfig?: TStateSetter | null);
11
+ protected onInit: (parameters: StateConfigCallbackParam<TState, TMetadata, TStateSetter>) => void;
12
+ protected onStateChanged: (parameters: StateChangesParam<TState, TMetadata, NonNullable<TStateSetter>>) => void;
13
+ protected abstract onInitialize: ({ setState, setMetadata, getMetadata, getState, actions, }: StateConfigCallbackParam<TState, TMetadata, TStateSetter>) => void;
14
+ protected abstract onChange: ({ setState, setMetadata, getMetadata, getState, actions, }: StateChangesParam<TState, TMetadata, NonNullable<TStateSetter>>) => void;
15
+ }
package/lib/bundle.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("react")):"function"==typeof define&&define.amd?define(["react"],e):"object"==typeof exports?exports["react-native-global-state-hooks"]=e(require("react")):t["react-native-global-state-hooks"]=e(t.react)}(this,(t=>{return e={774:(t,e,r)=>{"use strict";function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function o(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function a(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,i(n.key),n)}}function i(t){var e=function(t,e){if("object"!==n(t)||null===t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var o=r.call(t,"string");if("object"!==n(o))return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"===n(e)?e:String(e)}Object.defineProperty(e,"__esModule",{value:!0}),e.GlobalStore=void 0;var u=r(684),c=r(156),l=function(){function t(e){var r=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.state=e,this.setterConfig=a,this.subscribers=new Set,this.config={metadata:null},this.onInit=null,this.onStateChanged=null,this.onSubscribed=null,this.computePreventStateChange=null,this.onInitializeStore=function(){var t=r.onInit,e=r.config.onInit;if(t||e){var n=r.getConfigCallbackParam({});null==t||t(n),null==e||e(n)}},this.getStateClone=function(){return(0,u.clone)(r.state)},this.getMetadataClone=function(){var t,e;return(0,u.clone)(null!==(e=null===(t=r.config)||void 0===t?void 0:t.metadata)&&void 0!==e?e:null)},this.setState=function(t){var e=t.invokerSetState,n=t.state;r.state=n,null==e||e(n),r.subscribers.forEach((function(t){t!==e&&t(n)}))},this.setMetadata=function(t){var e,n="function"==typeof t?t(r.getMetadataClone()):t;r.config=Object.assign(Object.assign({},null!==(e=r.config)&&void 0!==e?e:{}),{metadata:n})},this.getConfigCallbackParam=function(t){var e=t.invokerSetState;return{setMetadata:r.setMetadata,getMetadata:r.getMetadataClone,getState:r.getStateClone,setState:r.getSetStateWrapper({invokerSetState:e}),actions:r.getStoreActionsMap({})}},this.getHook=function(){return function(){var t,e,n=(t=(0,c.useState)((function(){return r.state})),e=2,function(t){if(Array.isArray(t))return t}(t)||function(t,e){var r=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=r){var n,o,a,i,u=[],c=!0,l=!1;try{if(a=(r=r.call(t)).next,0===e){if(Object(r)!==r)return;c=!1}else for(;!(c=(n=a.call(r)).done)&&(u.push(n.value),u.length!==e);c=!0);}catch(t){l=!0,o=t}finally{try{if(!c&&null!=r.return&&(i=r.return(),Object(i)!==i))return}finally{if(l)throw o}}return u}}(t,e)||function(t,e){if(t){if("string"==typeof t)return o(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?o(t,e):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),a=n[0],i=n[1];return(0,c.useEffect)((function(){r.subscribers.add(i);var t=r.onSubscribed,e=r.config.onSubscribed;if(t||e){var n=r.getConfigCallbackParam({invokerSetState:i});null==t||t(n),null==e||e(n)}return function(){r.subscribers.delete(i)}}),[]),[a,r.getStateOrchestrator(i),r.getMetadataClone()]}},this.getHookDecoupled=function(){var t=r.getStateClone,e=r.getMetadataClone;return[t,r.getStateOrchestrator(),e]},this.getSetStateWrapper=function(){var t=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).invokerSetState;return function(e){r.computeSetState({invokerSetState:t,setter:e})}},this.hasStateCallbacks=function(){var t=r.computePreventStateChange,e=r.onStateChanged,n=r.config,o=n.computePreventStateChange,a=n.onStateChanged;return!!(t||o||e||a)},this.computeSetState=function(t){var e=t.setter,n=t.invokerSetState,o="function"==typeof e,a=r.getStateClone(),i=o?e(a):e,u=r.hasStateCallbacks(),c=u&&r.getStoreActionsMap({}),l=u&&r.getSetStateWrapper({invokerSetState:n}),s={setMetadata:r.setMetadata,getMetadata:r.getMetadataClone,setState:l,getState:r.getStateClone,actions:c,previousState:a,state:i},f=r.computePreventStateChange,v=r.config.computePreventStateChange;if(!f&&!v||!(null==f?void 0:f(s))&&!(null==v?void 0:v(s))){r.setState({invokerSetState:n,state:i});var g=r.onStateChanged,S=r.config.onStateChanged;(g||S)&&(null==g||g(s),null==S||S(s))}},this.getStoreActionsMap=function(t){var e=t.invokerSetState;if(!r.setterConfig)return null;var n=r.setterConfig,o=r.setMetadata,a=n,u=Object.keys(a),c=r.getSetStateWrapper({invokerSetState:e}),l=r.getStateClone,s=r.getMetadataClone,f=u.reduce((function(t,e){return Object.assign(Object.assign({},t),(r={},u=function(){for(var t=a[e],r=arguments.length,n=new Array(r),i=0;i<r;i++)n[i]=arguments[i];var u=t.apply(f,n);return"function"!=typeof u&&function(t){throw new Error("[WRONG CONFIGURATION!]: Every key inside the storeActionsConfig must be a higher order function that returns a function \n[".concat(t,"]: key is not a valid function, try something like this: \n{\n\n ").concat(t,": (param) => ({ setState, getState, setMetadata, getMetadata }) => {\n\n setState((state) => ({ ...state, ...param }))\n\n }\n\n}\n"))}(e),u.call(f,{setState:c,getState:l,setMetadata:o,getMetadata:s})},(n=i(n=e))in r?Object.defineProperty(r,n,{value:u,enumerable:!0,configurable:!0,writable:!0}):r[n]=u,r));var r,n,u}),{});return f},this.config=Object.assign({metadata:null},null!=n?n:{}),this.onInitializeStore()}var e,r;return e=t,(r=[{key:"getStateOrchestrator",value:function(t){return this.setterConfig?this.getStoreActionsMap({invokerSetState:t}):this.getSetStateWrapper({invokerSetState:t})}}])&&a(e.prototype,r),Object.defineProperty(e,"prototype",{writable:!1}),t}();e.GlobalStore=l},530:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0})},991:(t,e,r)=>{"use strict";var n=Object.create?function(t,e,r,n){void 0===n&&(n=r);var o=Object.getOwnPropertyDescriptor(e,r);o&&!("get"in o?!e.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,n,o)}:function(t,e,r,n){void 0===n&&(n=r),t[n]=e[r]},o=function(t,e){for(var r in t)"default"===r||Object.prototype.hasOwnProperty.call(e,r)||n(e,t,r)};Object.defineProperty(e,"__esModule",{value:!0}),o(r(684),e),o(r(530),e),o(r(774),e)},684:function(t){t.exports=(()=>{"use strict";var t={991:(t,e,r)=>{var n=Object.create?function(t,e,r,n){void 0===n&&(n=r);var o=Object.getOwnPropertyDescriptor(e,r);o&&!("get"in o?!e.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,n,o)}:function(t,e,r,n){void 0===n&&(n=r),t[n]=e[r]};Object.defineProperty(e,"__esModule",{value:!0}),function(t,e){for(var r in t)"default"===r||Object.prototype.hasOwnProperty.call(e,r)||n(e,t,r)}(r(729),e)},729:(t,e)=>{function r(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function o(t,e,r){return(e=function(t){var e=function(t,e){if("object"!==n(t)||null===t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var o=r.call(t,"string");if("object"!==n(o))return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"===n(e)?e:String(e)}(e))in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}Object.defineProperty(e,"__esModule",{value:!0}),e.formatToStore=e.formatFromStore=e.isPrimitive=e.isRegex=e.isDate=e.isString=e.isBoolean=e.isNumber=e.isNil=e.clone=void 0,e.clone=function(t){if((0,e.isPrimitive)(t)||(0,e.isDate)(t))return t;if(Array.isArray(t))return t.map((function(t){return(0,e.clone)(t)}));if(t instanceof Map){var r=Array.from(t.entries());return new Map(r.map((function(t){return(0,e.clone)(t)})))}if(t instanceof Set){var n=Array.from(t.values());return new Set(n.map((function(t){return(0,e.clone)(t)})))}return t instanceof RegExp?new RegExp(t.toString()):t instanceof Error?new Error(t.message):Object.keys(t).reduce((function(r,n){var a=t[n];return Object.assign(Object.assign({},r),o({},n,(0,e.clone)(a)))}),{})},e.isNil=function(t){return null==t},e.isNumber=function(t){return"number"==typeof t},e.isBoolean=function(t){return"boolean"==typeof t},e.isString=function(t){return"string"==typeof t},e.isDate=function(t){return t instanceof Date},e.isRegex=function(t){return t instanceof RegExp},e.isPrimitive=function(t){return(0,e.isNil)(t)||(0,e.isNumber)(t)||(0,e.isBoolean)(t)||(0,e.isString)(t)||"symbol"===n(t)},e.formatFromStore=function(t){return function(t){var n,a;if((0,e.isPrimitive)(t))return t;if("date"===(null==t?void 0:t.$t))return new Date(t.$v);if("map"===(null==t?void 0:t.$t)){var i=(null!==(n=t.$v)&&void 0!==n?n:[]).map((function(t){var n,o=(2,function(t){if(Array.isArray(t))return t}(n=t)||function(t,e){var r=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=r){var n,o,a,i,u=[],c=!0,l=!1;try{for(a=(r=r.call(t)).next,0;!(c=(n=a.call(r)).done)&&(u.push(n.value),2!==u.length);c=!0);}catch(t){l=!0,o=t}finally{try{if(!c&&null!=r.return&&(i=r.return(),Object(i)!==i))return}finally{if(l)throw o}}return u}}(n)||function(t,e){if(t){if("string"==typeof t)return r(t,2);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?r(t,2):void 0}}(n)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),a=o[0],i=o[1];return[a,(0,e.formatFromStore)(i)]}));return new Map(i)}if("set"===(null==t?void 0:t.$t)){var u=null!==(a=t.$v)&&void 0!==a?a:[].map((function(t){return(0,e.formatFromStore)(t)}));return new Set(u)}return"regex"===(null==t?void 0:t.$t)?new RegExp(t.$v):"error"===(null==t?void 0:t.$t)?new Error(t.$v):Array.isArray(t)?t.map((function(t){return(0,e.formatFromStore)(t)})):Object.keys(t).reduce((function(r,n){var a=t[n];return Object.assign(Object.assign({},r),o({},n,(0,e.formatFromStore)(a)))}),{})}((0,e.clone)(t))},e.formatToStore=function(t){var r,n=(arguments.length>1&&void 0!==arguments[1]?arguments[1]:{stringify:!1}).stringify,a=(r=(0,e.clone)(t),(0,e.isPrimitive)(r)?r:Array.isArray(r)?r.map((function(t){return(0,e.formatToStore)(t)})):r instanceof Map?{$t:"map",$v:Array.from(r.entries()).map((function(t){return(0,e.formatToStore)(t)}))}:r instanceof Set?{$t:"set",$v:Array.from(r.values()).map((function(t){return(0,e.formatToStore)(t)}))}:(0,e.isDate)(r)?{$t:"date",$v:r.toISOString()}:(0,e.isRegex)(r)?{$t:"regex",$v:r.toString()}:r instanceof Error?{$t:"error",$v:r.message}:Object.keys(r).reduce((function(t,n){var a=r[n];return Object.assign(Object.assign({},t),o({},n,(0,e.formatToStore)(a)))}),{}));return n?JSON.stringify(a):a}}},e={};return function r(n){var o=e[n];if(void 0!==o)return o.exports;var a=e[n]={exports:{}};return t[n](a,a.exports,r),a.exports}(991)})()},156:e=>{"use strict";e.exports=t}},r={},function t(n){var o=r[n];if(void 0!==o)return o.exports;var a=r[n]={exports:{}};return e[n].call(a.exports,a,a.exports,t),a.exports}(991);var e,r}));
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("react")):"function"==typeof define&&define.amd?define(["react"],e):"object"==typeof exports?exports["react-native-global-state-hooks"]=e(require("react")):t["react-native-global-state-hooks"]=e(t.react)}(this,(t=>{return e={774:(t,e,r)=>{"use strict";function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function o(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}function i(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,a(n.key),n)}}function a(t){var e=function(t,e){if("object"!==n(t)||null===t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var o=r.call(t,"string");if("object"!==n(o))return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"===n(e)?e:String(e)}Object.defineProperty(e,"__esModule",{value:!0}),e.createGlobalHook=e.GlobalStore=void 0;var u=r(156),c=function(){function t(e){var r=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.setterConfig=i,this.subscribers=new Set,this.config={metadata:null},this.onInit=null,this.onStateChanged=null,this.onSubscribed=null,this.computePreventStateChange=null,this.initialize=function(){var t=r.onInit,e=r.config.onInit;if(t||e){var n=r.getConfigCallbackParam({});null==t||t(n),null==e||e(n)}},this.setState=function(t){var e=t.invokerSetState,n=t.state;r.stateWrapper={state:n},null==e||e({state:n}),r.subscribers.forEach((function(t){t!==e&&t({state:n})}))},this.setMetadata=function(t){var e,n,o="function"==typeof t?t(null!==(e=r.config.metadata)&&void 0!==e?e:null):t;r.config=Object.assign(Object.assign({},null!==(n=r.config)&&void 0!==n?n:{}),{metadata:o})},this.getConfigCallbackParam=function(t){var e=t.invokerSetState;return{setMetadata:r.setMetadata,getMetadata:function(){return r.config.metadata},getState:function(){return r.stateWrapper.state},setState:r.getSetStateWrapper({invokerSetState:e}),actions:r.getStoreActionsMap()}},this.getHook=function(){return function(){var t,e,n=(t=(0,u.useState)((function(){return r.stateWrapper})),e=2,function(t){if(Array.isArray(t))return t}(t)||function(t,e){var r=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=r){var n,o,i,a,u=[],c=!0,f=!1;try{if(i=(r=r.call(t)).next,0===e){if(Object(r)!==r)return;c=!1}else for(;!(c=(n=i.call(r)).done)&&(u.push(n.value),u.length!==e);c=!0);}catch(t){f=!0,o=t}finally{try{if(!c&&null!=r.return&&(a=r.return(),Object(a)!==a))return}finally{if(f)throw o}}return u}}(t,e)||function(t,e){if(t){if("string"==typeof t)return o(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?o(t,e):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),i=n[0],a=n[1];(0,u.useEffect)((function(){r.subscribers.add(a);var t=r.onSubscribed,e=r.config.onSubscribed;if(t||e){var n=r.getConfigCallbackParam({invokerSetState:a});null==t||t(n),null==e||e(n)}return function(){r.subscribers.delete(a)}}),[]);var c=r.getStateOrchestrator(a);return[i.state,c,r.config.metadata]}},this.getHookDecoupled=function(){return[function(){return r.stateWrapper.state},r.getStateOrchestrator(),function(){return r.config.metadata}]},this.getSetStateWrapper=function(){var t=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).invokerSetState;return function(e){var n=(arguments.length>1&&void 0!==arguments[1]?arguments[1]:{}).forceUpdate;r.computeSetState({invokerSetState:t,setter:e,forceUpdate:n})}},this.hasStateCallbacks=function(){var t=r.computePreventStateChange,e=r.onStateChanged,n=r.config,o=n.computePreventStateChange,i=n.onStateChanged;return!!(t||o||e||i)},this.computeSetState=function(t){var e=t.setter,n=t.invokerSetState,o=t.forceUpdate,i="function"==typeof e,a=r.stateWrapper.state,u=i?e(a):e;if(o||!Object.is(r.stateWrapper.state,u)){var c=r.hasStateCallbacks(),f=c&&r.getStoreActionsMap({}),s=c&&r.getSetStateWrapper({invokerSetState:n}),l={setMetadata:r.setMetadata,getMetadata:function(){return r.config.metadata},setState:s,getState:function(){return r.stateWrapper.state},actions:f,previousState:a,state:u},p=r.computePreventStateChange,v=r.config.computePreventStateChange;if((p||v)&&((null==p?void 0:p(l))||(null==v?void 0:v(l))))return;r.setState({invokerSetState:n,state:u});var y=r.onStateChanged,b=r.config.onStateChanged;(y||b)&&(null==y||y(l),null==b||b(l))}},this.getStoreActionsMap=function(){var t=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).invokerSetState;if(!r.setterConfig)return null;var e=r.setterConfig,n=r.setMetadata,o=e,i=Object.keys(o),u=r.getSetStateWrapper({invokerSetState:t}),c=function(){return r.stateWrapper.state},f=function(){return r.config.metadata},s=i.reduce((function(t,e){return Object.assign(Object.assign({},t),(r={},l=function(){for(var t=o[e],r=arguments.length,i=new Array(r),a=0;a<r;a++)i[a]=arguments[a];var l=t.apply(s,i);return"function"!=typeof l&&function(t){throw new Error("[WRONG CONFIGURATION!]: Every key inside the storeActionsConfig must be a higher order function that returns a function \n[".concat(t,"]: key is not a valid function, try something like this: \n{\n\n ").concat(t,": (param) => ({ setState, getState, setMetadata, getMetadata }) => {\n\n setState((state) => ({ ...state, ...param }))\n\n }\n\n}\n"))}(e),l.call(s,{setState:u,getState:c,setMetadata:n,getMetadata:f,actions:s})},(i=a(i=e))in r?Object.defineProperty(r,i,{value:l,enumerable:!0,configurable:!0,writable:!0}):r[i]=l,r));var r,i,l}),{});return s},this.stateWrapper={state:e},this.config=Object.assign({metadata:null},null!=n?n:{}),this.constructor!==t||this.initialize()}var e,r;return e=t,(r=[{key:"state",get:function(){return this.stateWrapper.state}},{key:"getStateOrchestrator",value:function(t){return this.setterConfig?this.getStoreActionsMap({invokerSetState:t}):this.getSetStateWrapper({invokerSetState:t})}}])&&i(e.prototype,r),Object.defineProperty(e,"prototype",{writable:!1}),t}();e.GlobalStore=c,e.createGlobalHook=function(t){return new c(t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},arguments.length>2&&void 0!==arguments[2]?arguments[2]:null).getHook()}},530:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0})},195:(t,e,r)=>{"use strict";function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function o(t,e){return o=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},o(t,e)}function i(t){return i=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)},i(t)}Object.defineProperty(e,"__esModule",{value:!0}),e.GlobalStoreAbstract=void 0;var a=function(t){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&o(t,e)}(c,t);var e,r,a,u=(r=c,a=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}(),function(){var t,e=i(r);if(a){var o=i(this).constructor;t=Reflect.construct(e,arguments,o)}else t=e.apply(this,arguments);return function(t,e){if(e&&("object"===n(e)||"function"==typeof e))return e;if(void 0!==e)throw new TypeError("Derived constructors may only return object or undefined");return function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t)}(this,t)});function c(t){var e,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,c),(e=u.call(this,t,r,n)).onInit=function(t){e.onInitialize(t)},e.onStateChanged=function(t){e.onChange(t)},e}return e=c,Object.defineProperty(e,"prototype",{writable:!1}),e}(r(774).GlobalStore);e.GlobalStoreAbstract=a},991:(t,e,r)=>{"use strict";var n=Object.create?function(t,e,r,n){void 0===n&&(n=r);var o=Object.getOwnPropertyDescriptor(e,r);o&&!("get"in o?!e.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,n,o)}:function(t,e,r,n){void 0===n&&(n=r),t[n]=e[r]},o=function(t,e){for(var r in t)"default"===r||Object.prototype.hasOwnProperty.call(e,r)||n(e,t,r)};Object.defineProperty(e,"__esModule",{value:!0}),o(r(684),e),o(r(530),e),o(r(774),e),o(r(195),e)},684:function(t){t.exports=(()=>{"use strict";var t={991:(t,e,r)=>{var n=Object.create?function(t,e,r,n){void 0===n&&(n=r);var o=Object.getOwnPropertyDescriptor(e,r);o&&!("get"in o?!e.__esModule:o.writable||o.configurable)||(o={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,n,o)}:function(t,e,r,n){void 0===n&&(n=r),t[n]=e[r]};Object.defineProperty(e,"__esModule",{value:!0}),function(t,e){for(var r in t)"default"===r||Object.prototype.hasOwnProperty.call(e,r)||n(e,t,r)}(r(729),e)},729:(t,e)=>{function r(t){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},r(t)}function n(t,e,n){return(e=function(t){var e=function(t,e){if("object"!==r(t)||null===t)return t;var n=t[Symbol.toPrimitive];if(void 0!==n){var o=n.call(t,"string");if("object"!==r(o))return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"===r(e)?e:String(e)}(e))in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function o(t,e){if(t){if("string"==typeof t)return i(t,e);var r=Object.prototype.toString.call(t).slice(8,-1);return"Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r?Array.from(t):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?i(t,e):void 0}}function i(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=new Array(e);r<e;r++)n[r]=t[r];return n}Object.defineProperty(e,"__esModule",{value:!0}),e.formatToStore=e.formatFromStore=e.isPrimitive=e.isFunction=e.isRegex=e.isDate=e.isString=e.isBoolean=e.isNumber=e.isNil=e.clone=void 0,e.clone=function(t){var r,a=(arguments.length>1&&void 0!==arguments[1]?arguments[1]:{}).shallow;if((0,e.isPrimitive)(t)||(0,e.isDate)(t))return t;if(Array.isArray(t))return a?function(t){if(Array.isArray(t))return i(t)}(r=t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(r)||o(r)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}():t.map((function(t){return(0,e.clone)(t)}));if(t instanceof Map){var u=Array.from(t.entries());return a?new Map(u):new Map(u.map((function(t){return(0,e.clone)(t)})))}if(t instanceof Set){var c=Array.from(t.values());return a?new Set(c):new Set(c.map((function(t){return(0,e.clone)(t)})))}return t instanceof RegExp?new RegExp(t.toString()):(0,e.isFunction)(t)?a?t:Object.create(t):a?Object.assign({},t):t instanceof Error?new Error(t.message):Object.keys(t).reduce((function(r,o){var i=t[o];return Object.assign(Object.assign({},r),n({},o,(0,e.clone)(i)))}),{})},e.isNil=function(t){return null==t},e.isNumber=function(t){return"number"==typeof t},e.isBoolean=function(t){return"boolean"==typeof t},e.isString=function(t){return"string"==typeof t},e.isDate=function(t){return t instanceof Date},e.isRegex=function(t){return t instanceof RegExp},e.isFunction=function(t){return"function"==typeof t||t instanceof Function},e.isPrimitive=function(t){return(0,e.isNil)(t)||(0,e.isNumber)(t)||(0,e.isBoolean)(t)||(0,e.isString)(t)||"symbol"===r(t)},e.formatFromStore=function(t){return function(t){var r,i;if((0,e.isPrimitive)(t))return t;if("date"===(null==t?void 0:t.$t))return new Date(t.$v);if("map"===(null==t?void 0:t.$t)){var a=(null!==(r=t.$v)&&void 0!==r?r:[]).map((function(t){var r,n=(2,function(t){if(Array.isArray(t))return t}(r=t)||function(t,e){var r=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=r){var n,o,i,a,u=[],c=!0,f=!1;try{for(i=(r=r.call(t)).next,0;!(c=(n=i.call(r)).done)&&(u.push(n.value),2!==u.length);c=!0);}catch(t){f=!0,o=t}finally{try{if(!c&&null!=r.return&&(a=r.return(),Object(a)!==a))return}finally{if(f)throw o}}return u}}(r)||o(r,2)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),i=n[0],a=n[1];return[i,(0,e.formatFromStore)(a)]}));return new Map(a)}if("set"===(null==t?void 0:t.$t)){var u=null!==(i=t.$v)&&void 0!==i?i:[].map((function(t){return(0,e.formatFromStore)(t)}));return new Set(u)}return"regex"===(null==t?void 0:t.$t)?new RegExp(t.$v):"error"===(null==t?void 0:t.$t)?new Error(t.$v):Array.isArray(t)?t.map((function(t){return(0,e.formatFromStore)(t)})):"function"===(null==t?void 0:t.$t)?Function("(".concat(t.$v,")(...arguments)")):Object.keys(t).reduce((function(r,o){var i=t[o];return Object.assign(Object.assign({},r),n({},o,(0,e.formatFromStore)(i)))}),{})}((arguments.length>1&&void 0!==arguments[1]?arguments[1]:{}).jsonParse?JSON.parse(t):(0,e.clone)(t))},e.formatToStore=function(t){var o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{stringify:!1},i=o.stringify,a=o.validator,u=o.excludeTypes,c=o.excludeKeys,f=new Set(null!=u?u:[]),s=new Set(null!=c?c:[]),l=f.size||s.size,p=null!=a?a:function(t){var e=t.key,n=t.value;if(!l)return!0;var o=s.has(e),i=f.has(r(n));return!o&&!i},v=function t(r){if((0,e.isPrimitive)(r))return r;if(Array.isArray(r))return r.map((function(e){return t(e)}));if(r instanceof Map)return{$t:"map",$v:Array.from(r.entries()).map((function(e){return t(e)}))};if(r instanceof Set)return{$t:"set",$v:Array.from(r.values()).map((function(e){return t(e)}))};if((0,e.isDate)(r))return{$t:"date",$v:r.toISOString()};if((0,e.isRegex)(r))return{$t:"regex",$v:r.toString()};if((0,e.isFunction)(r)){var o;try{o={$t:"function",$v:r.toString()}}catch(t){o={$t:"error",$v:"Error: Could not serialize function"}}return o}return r instanceof Error?{$t:"error",$v:r.message}:Object.keys(r).reduce((function(e,o){var i=r[o],a=t(i);return p({obj:r,key:o,value:a})?Object.assign(Object.assign({},e),n({},o,t(i))):e}),{})}((0,e.clone)(t));return i?JSON.stringify(v):v}}},e={};return function r(n){var o=e[n];if(void 0!==o)return o.exports;var i=e[n]={exports:{}};return t[n](i,i.exports,r),i.exports}(991)})()},156:e=>{"use strict";e.exports=t}},r={},function t(n){var o=r[n];if(void 0!==o)return o.exports;var i=r[n]={exports:{}};return e[n].call(i.exports,i,i.exports,t),i.exports}(991);var e,r}));
package/lib/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from 'json-storage-formatter';
2
2
  export * from './GlobalStore.types';
3
3
  export * from './GlobalStore';
4
+ export * from './GlobalStoreAbstract';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-global-state-hooks",
3
- "version": "3.0.5",
3
+ "version": "3.0.7",
4
4
  "description": "This is a package to easily handling global-state across your react-native-components No-redux",
5
5
  "main": "lib/bundle.js",
6
6
  "types": "lib/index.d.ts",
@@ -80,6 +80,6 @@
80
80
  }
81
81
  },
82
82
  "dependencies": {
83
- "json-storage-formatter": "^1.0.7"
83
+ "json-storage-formatter": "^1.0.8"
84
84
  }
85
85
  }
package/README.advance.md DELETED
@@ -1,123 +0,0 @@
1
- ## Creating hooks with reusable actions
2
-
3
- Let's say you want to have a STATE with a specific set of actions that you could be reused. With this library is pretty easy to accomplish. Let's create **increase** and **decrease** actions to our count-store. **useCountGlobal.ts**:
4
-
5
- ```JSX
6
- import {
7
- IActionCollectionConfig,
8
- IActionCollectionResult,
9
- StateSetter,
10
- } from 'react-native-global-state-hooks/lib/GlobalStoreTypes';
11
-
12
- /**
13
- * When using a custom api, the getHook and getHookDecoupled will not longer return directly the setter,
14
- * intead they will return and api with the specific actions and mutations defined for the store
15
- * Creating a configuration object for our api
16
- */
17
- const countActionsApi: IActionCollectionConfig<number> = {
18
- /* Decrease the value of the count */
19
- decrease(decrease: number) {
20
- /**
21
- * We need to return the async function that is gonna take care of the state mutation or actions
22
- */
23
- return async (setter: StateSetter<number>, state: number) => {
24
- /**
25
- * Next, we perfom whatever modification we want on top of the store
26
- */
27
- return setter(state - decrease);
28
- };
29
- },
30
-
31
- //* Lets add a new action to increase the value of the count */
32
- increase(increase: number) {
33
-
34
- return async (setter: StateSetter<number>, state: number) => {
35
- return setter(state + increase);
36
- };
37
- },
38
- };
39
-
40
- /**
41
- * Now our getHook and getHookDecoupled are gonna return our custom api instead of the StateSetter,
42
- * This will allow us to have more control over our store since the mutations of the same are gonna be limitated
43
- */
44
- const countStore = new GlobalStore(0, countActionsApi);
45
- ```
46
-
47
- If we remove all the explanatory comments the code will look like this:
48
-
49
- ```TS
50
- const countStore = new GlobalStore(0, {
51
- decrease(decrease: number) {
52
- return (setter: StateSetter<number>, state: number) =>
53
- setter(state - decrease);
54
- },
55
-
56
- increase(increase: number) {
57
- return (setter: StateSetter<number>, state: number) =>
58
- setter(state + increase);
59
- },
60
- } as IActionCollectionConfig<number>);
61
- ```
62
-
63
- Now lets get our new global hook with specific API
64
-
65
- ```TS
66
- export interface ICountActions
67
- extends IActionCollectionResult<number, IActionCollectionConfig<number>> {
68
- decrease: (decrease: number) => Promise<number>;
69
- increase: (increase: number) => Promise<number>;
70
- }
71
-
72
- /**
73
- * The ICountActions interface is optional but it allow you yo get more accurate results for the typescript autocompletes and validations, ignore this if you are not using TS
74
- */
75
- export const useCountGlobal = countStore.getHook<ICountActions>();
76
- ```
77
-
78
- And that's it! the result of our useCountGlobal will return our actions instead of a simple setter... Let's see how that will look:
79
-
80
- ```JSX
81
- import { useCountGlobal } from './useCountGlobal'
82
-
83
- const MyComponent: Reac.FC = () => {
84
- const [count, countActions] = useCountGlobal();
85
-
86
- // this functions are strongly typed
87
- const increaseClick = () => countActions.increase(1);
88
- const decreaseClick = () => countActions.decrease(1);
89
-
90
- return (<>
91
- <Text>{count}<Text/>
92
- <Button onPress={increaseClick} title={'increase'} />
93
- <Button onPress={decreaseClick} title={'decrease'} />
94
- </>);
95
- }
96
-
97
- ```
98
-
99
- ## Customize persist storage
100
-
101
- Let suppose you don't like **async-storage** or you also want to implement some kind of encrypt-process. You could easily extend the **GlobalStore** Class, and customize your persist store implementation.
102
-
103
- ```JSX
104
- import GlobalState from 'react-native-global-state-hooks';
105
- import secureStorage from 'react-native-secure-storage';
106
- import { IActionCollection } from 'react-native-global-state-hooks/lib/GlobalStoreTypes';
107
-
108
- export class SecureGlobalState<
109
- IState,
110
- IPersist extends string | null = null,
111
- IsPersist extends boolean = IPersist extends null ? false : true,
112
- IActions extends IActionCollection<IState> | null = null
113
- > extends GlobalState<IState, IPersist, IsPersist, IActions> {
114
-
115
- protected asyncStorageGetItem = () => secureStorage.getItem(this.persistStoreAs as string, config);
116
-
117
- /** value is a json string*/
118
- protected asyncStorageSetItem = (value: string) => secureStorage.setItem(this.persistStoreAs as string, value, config);
119
-
120
- }
121
-
122
- export default SecureGlobalState;
123
- ```