react-native-global-state-hooks 7.0.2 → 8.0.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.
- package/GlobalStore.d.ts +29 -0
- package/GlobalStore.js +1 -0
- package/GlobalStoreAbstract.d.ts +9 -0
- package/GlobalStoreAbstract.js +1 -0
- package/README.md +340 -334
- package/asyncStorageWrapper.d.ts +8 -0
- package/asyncStorageWrapper.js +1 -0
- package/bundle.js +1 -0
- package/combineRetrieverAsynchronously.d.ts +1 -0
- package/combineRetrieverAsynchronously.js +1 -0
- package/combineRetrieverEmitterAsynchronously.d.ts +1 -0
- package/combineRetrieverEmitterAsynchronously.js +1 -0
- package/createContext.d.ts +1 -0
- package/createContext.js +1 -0
- package/createCustomGlobalState.d.ts +22 -0
- package/createCustomGlobalState.js +1 -0
- package/createGlobalState.d.ts +20 -0
- package/createGlobalState.js +1 -0
- package/debounce.d.ts +1 -0
- package/debounce.js +1 -0
- package/getAsyncStorageItem.d.ts +2 -0
- package/getAsyncStorageItem.js +1 -0
- package/index.d.ts +23 -0
- package/isRecord.d.ts +1 -0
- package/isRecord.js +1 -0
- package/package.json +94 -8
- package/setAsyncStorageItem.d.ts +2 -0
- package/setAsyncStorageItem.js +1 -0
- package/shallowCompare.d.ts +1 -0
- package/shallowCompare.js +1 -0
- package/throwWrongKeyOnActionCollectionConfig.d.ts +1 -0
- package/throwWrongKeyOnActionCollectionConfig.js +1 -0
- package/types.d.ts +83 -0
- package/types.js +1 -0
- package/uniqueId.d.ts +1 -0
- package/uniqueId.js +1 -0
- package/uniqueSymbol.d.ts +1 -0
- package/uniqueSymbol.js +1 -0
- package/useConstantValueRef.d.ts +1 -0
- package/useConstantValueRef.js +1 -0
- package/webpack.config.js +89 -0
- package/lib/bundle.js +0 -2
- package/lib/bundle.js.LICENSE.txt +0 -1
- package/lib/src/GlobalStore.context.d.ts +0 -6
- package/lib/src/GlobalStore.d.ts +0 -28
- package/lib/src/GlobalStore.functionHooks.d.ts +0 -19
- package/lib/src/GlobalStore.types.d.ts +0 -124
- package/lib/src/GlobalStore.utils.d.ts +0 -16
- package/lib/src/GlobalStoreAbstract.d.ts +0 -16
- package/lib/src/index.d.ts +0 -12
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ The best part? [react-hooks-global-states](https://www.npmjs.com/package/react-h
|
|
|
23
23
|
We are gonna create a global state hook **useCount** with one line of code.
|
|
24
24
|
|
|
25
25
|
```ts
|
|
26
|
-
import { createGlobalState } from "react-native-global-state-hooks";
|
|
26
|
+
import { createGlobalState } from "react-native-global-state-hooks/createGlobalState";
|
|
27
27
|
|
|
28
28
|
export const useCount = createGlobalState(0);
|
|
29
29
|
```
|
|
@@ -68,76 +68,154 @@ The metadata and components will be updated and re-rendered even if there's no d
|
|
|
68
68
|
What if you already have a global state that you want to subscribe to, but you don't want your component to listen to all the changes of the state, only a small portion of it? Let's create a more complex **state**
|
|
69
69
|
|
|
70
70
|
```ts
|
|
71
|
-
import { createGlobalState } from
|
|
71
|
+
import { createGlobalState } from 'react-hooks-global-states';
|
|
72
72
|
|
|
73
73
|
export const useContacts = createGlobalState({
|
|
74
74
|
isLoading: true,
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
entities: Contact[],
|
|
76
|
+
selected: Set<number>,
|
|
77
77
|
});
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
Now, let's say we want to
|
|
81
|
-
|
|
82
|
-
**FilterBar.tsx**
|
|
80
|
+
Now, let's say we have a situation where we want to access only the list of contacts. We don't care about the rest of the state.
|
|
83
81
|
|
|
84
82
|
```tsx
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
);
|
|
83
|
+
// That's it. With that simple selector, we now get the list of contacts,
|
|
84
|
+
// and the component will only re-render if the property **entities** changes on the global state
|
|
85
|
+
const [contacts] = useContacts((state) => state.entities]);
|
|
88
86
|
|
|
89
87
|
return (
|
|
90
|
-
<
|
|
88
|
+
<ul>
|
|
91
89
|
{contacts.map((contact) => (
|
|
92
|
-
<
|
|
90
|
+
<li key={contact.id}>{contact.name}</li>
|
|
93
91
|
))}
|
|
94
|
-
</
|
|
92
|
+
</ul>
|
|
95
93
|
);
|
|
96
94
|
```
|
|
97
95
|
|
|
98
|
-
|
|
96
|
+
What about special cases, like when you have a map instead of an array and want to extract a list of contacts? It's common to use selectors that return a new array, but this can cause React to re-render because the new array has a different reference than the previous one.
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
export const useContacts = createGlobalState({
|
|
100
|
+
isLoading: true,
|
|
101
|
+
entities: Map<number, Contact>,
|
|
102
|
+
selected: Set<number>,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// The selector is simply a standard selector used to extract the values from the map.
|
|
106
|
+
|
|
107
|
+
const [contacts] = useContacts((state) => [...state.entities.values()], {
|
|
108
|
+
// The isEqualRoots function allows you to create your own validation logic for determining when to recompute the selector.
|
|
109
|
+
isEqualRoot: (a, b) => a.entities === b.entities,
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Okay, everything works when the changes come from the state, but what happens if I want to recompute the selector based on the internal state of the component?
|
|
99
114
|
|
|
100
|
-
|
|
115
|
+
**component.ts**
|
|
101
116
|
|
|
102
117
|
```tsx
|
|
103
118
|
const [filter, setFilter] = useState("");
|
|
104
119
|
|
|
105
120
|
const [contacts] = useContacts(
|
|
106
|
-
(state) => state.
|
|
121
|
+
(state) => [...state.entities.values()].filter((item) => item.name.includes(filter)),
|
|
107
122
|
{
|
|
123
|
+
isEqualRoot: (a, b) => a.entities === b.entities,
|
|
108
124
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*/
|
|
113
|
-
isEqualRoot: (r1, r2) => r1.filter === r2.filter,
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* You can use the `isEqual` to validate if the values after the selector are equal.
|
|
117
|
-
* This validation will run after the selector computed a new value...
|
|
118
|
-
* and if the result is true it will prevent the re-render of the component.
|
|
119
|
-
*/
|
|
120
|
-
isEqual: (filter1, filter2) => filter1 === filter2,
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* You can use the `dependencies` array as with regular hooks to to force the recomputation of the selector.
|
|
124
|
-
* Is important ot mention that changes in the dependencies will not trigger a re-render of the component...
|
|
125
|
-
* Instead the recomputation of the selector will returned immediately.
|
|
126
|
-
*/
|
|
125
|
+
* Easy to understand, right? With the dependencies prop, you can,
|
|
126
|
+
* just like with any other hook, provide a collection of values that will be compared during each render cycle
|
|
127
|
+
* to determine if the selector should be recomputed.*/
|
|
127
128
|
dependencies: [filter],
|
|
128
129
|
}
|
|
129
130
|
);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
And finally, what if you need to reuse this selector throughout your application and don't want to duplicate code?
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
export const useContacts = createGlobalState({
|
|
137
|
+
isLoading: true,
|
|
138
|
+
entities: Map<number, Contact>,
|
|
139
|
+
selected: Set<number>,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const useContactsArray = useContacts.createSelectorHook((state) => [...state.entities.values()], {
|
|
143
|
+
isEqualRoot: (a, b) => a.entities === b.entities,
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Now inside your component just call the new hook
|
|
148
|
+
|
|
149
|
+
**component.ts**
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
const [filter, setFilter] = useState("");
|
|
153
|
+
|
|
154
|
+
const [contacts] = useContactsArray((entities) => entities.name.includes(filter), {
|
|
155
|
+
dependencies: [filter],
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Or you can create another selectorHook from your **useContactsArray**
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
const useContactsArray = useContacts.createSelectorHook((state) => [...state.entities.values()], {
|
|
163
|
+
isEqualRoot: (a, b) => a.entities === b.entities,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const useContactsLength = useContactsArray.createSelectorHook((entities) => entities.length);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Or you can create a custom hook
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
const useFilteredContacts = (filter: string) => {
|
|
173
|
+
const [contacts] = useContactsArray((entities) => entities.name.includes(filter), {
|
|
174
|
+
dependencies: [filter],
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
return contacts;
|
|
178
|
+
};
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
To summarize
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
const [filter, setFilter] = useState("");
|
|
185
|
+
|
|
186
|
+
const [contacts] = useContacts((state) => state.contacts.filter((contact) => contact.name.includes(filter)), {
|
|
187
|
+
/**
|
|
188
|
+
* You can use the `isEqualRoot` to validate if the values before the selector are equal.
|
|
189
|
+
* This validation will run before `isEqual` and if the result is true the selector will not be recomputed.
|
|
190
|
+
* If the result is true the re-render of the component will be prevented.
|
|
191
|
+
*/
|
|
192
|
+
isEqualRoot: (r1, r2) => r1.filter === r2.filter,
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* You can use the `isEqual` to validate if the values after the selector are equal.
|
|
196
|
+
* This validation will run after the selector computed a new value...
|
|
197
|
+
* and if the result is true it will prevent the re-render of the component.
|
|
198
|
+
*/
|
|
199
|
+
isEqual: (filter1, filter2) => filter1 === filter2,
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* You can use the `dependencies` array as with regular hooks to to force the recomputation of the selector.
|
|
203
|
+
* Is important ot mention that changes in the dependencies will not trigger a re-render of the component...
|
|
204
|
+
* Instead the recomputation of the selector will returned immediately.
|
|
205
|
+
*/
|
|
206
|
+
dependencies: [filter],
|
|
207
|
+
});
|
|
130
208
|
|
|
131
209
|
return (
|
|
132
|
-
<
|
|
210
|
+
<ul>
|
|
133
211
|
{contacts.map((contact) => (
|
|
134
|
-
<
|
|
212
|
+
<li key={contact.id}>{contact.name}</li>
|
|
135
213
|
))}
|
|
136
|
-
</
|
|
214
|
+
</ul>
|
|
137
215
|
);
|
|
138
216
|
```
|
|
139
217
|
|
|
140
|
-
If you want to perform a shallow comparison between the previous and new values, you can use the **shallowCompare** function from the library.
|
|
218
|
+
Btw, If you want to perform a shallow comparison between the previous and new values, you can use the **shallowCompare** function from the library.
|
|
141
219
|
|
|
142
220
|
```TSX
|
|
143
221
|
({
|
|
@@ -148,29 +226,23 @@ If you want to perform a shallow comparison between the previous and new values,
|
|
|
148
226
|
})
|
|
149
227
|
```
|
|
150
228
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
It will be super common to have the necessity of reusing a specific **selector**, and it can be a little annoying to have to do the same thing again and again. Right?
|
|
229
|
+
Just remember, you can select or derive different values from the global state endlessly, but the state mutator will remain the same throughout the hooks.
|
|
154
230
|
|
|
155
|
-
|
|
231
|
+
More examples:
|
|
156
232
|
|
|
157
233
|
```ts
|
|
158
|
-
const useFilter =
|
|
159
|
-
```
|
|
234
|
+
const useFilter = useContacts.createSelectorHook(({ filter }) => filter);
|
|
160
235
|
|
|
161
|
-
|
|
236
|
+
const useContactsArray = useContacts.createSelectorHook(({ items }) => items);
|
|
162
237
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
```ts
|
|
166
|
-
const [{ filter }, setState] = useFilter();
|
|
238
|
+
const useContactsLength = useContactsArray.createSelectorHook((items) => items.length);
|
|
167
239
|
|
|
168
|
-
|
|
169
|
-
<TextInput onChangeText={() => setState((state) => ({ ...state, filter }))} />
|
|
170
|
-
);
|
|
240
|
+
const useIsContactsEmpty = useContactsLength.createSelectorHook((length) => !length);
|
|
171
241
|
```
|
|
172
242
|
|
|
173
|
-
|
|
243
|
+
It can't get any simpler, right? Everything is connected, everything is reactive. Plus, these hooks are strongly typed, so if you're working with **TypeScript**, you'll absolutely love it.
|
|
244
|
+
|
|
245
|
+
Each selector hook is reactive only to the fragment/derived of the state returned by the selector. And again you can optimize it by using the **isEqualRoot** and **isEqual** functions, which help avoid recomputing the selector if the root state or the fragment hasn't changed.
|
|
174
246
|
|
|
175
247
|
# State actions
|
|
176
248
|
|
|
@@ -181,30 +253,29 @@ By defining a custom API for the **useContacts**, we can encapsulate and expose
|
|
|
181
253
|
```ts
|
|
182
254
|
import { createGlobalState } from "react-native-global-state-hooks";
|
|
183
255
|
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
type State = typeof initialState;
|
|
191
|
-
|
|
192
|
-
export const useContacts = createGlobalState(initialState, {
|
|
193
|
-
// this are the actions available for this state
|
|
194
|
-
actions: {
|
|
195
|
-
setFilter(filter: string) {
|
|
196
|
-
return ({ setState }: StoreTools<State>) => {
|
|
197
|
-
setState((state) => ({
|
|
198
|
-
...state,
|
|
199
|
-
filter,
|
|
200
|
-
}));
|
|
201
|
-
};
|
|
202
|
-
},
|
|
203
|
-
} as const,
|
|
204
|
-
onInit: async ({ setState }: StoreTools<State>) => {
|
|
205
|
-
// fetch contacts
|
|
256
|
+
export const useContacts = createGlobalState(
|
|
257
|
+
{
|
|
258
|
+
isLoading: true,
|
|
259
|
+
filter: "",
|
|
260
|
+
items: [] as Contact[],
|
|
206
261
|
},
|
|
207
|
-
|
|
262
|
+
{
|
|
263
|
+
// this are the actions available for this state
|
|
264
|
+
actions: {
|
|
265
|
+
setFilter(filter: string) {
|
|
266
|
+
return ({ setState }) => {
|
|
267
|
+
setState((state) => ({
|
|
268
|
+
...state,
|
|
269
|
+
filter,
|
|
270
|
+
}));
|
|
271
|
+
};
|
|
272
|
+
},
|
|
273
|
+
} as const,
|
|
274
|
+
onInit: ({ setState }) => {
|
|
275
|
+
// fetch contacts
|
|
276
|
+
},
|
|
277
|
+
}
|
|
278
|
+
);
|
|
208
279
|
```
|
|
209
280
|
|
|
210
281
|
That's it! In this updated version, the **useContacts** hook will no longer return [**state**, **stateMutator**] but instead will return [**state**, **actions**]. This change will provide a more intuitive and convenient way to access and interact with the state and its associated actions.
|
|
@@ -237,33 +308,22 @@ It can't get any simpler, right? Everything is connected, everything is reactive
|
|
|
237
308
|
|
|
238
309
|
# State Controls
|
|
239
310
|
|
|
240
|
-
|
|
311
|
+
If you need to access the global state outside of a component or a hook without subscribing to state changes, or even inside a **ClassComponent**, you can use:
|
|
241
312
|
|
|
242
|
-
|
|
313
|
+
```tsx
|
|
314
|
+
useContacts.stateControls: () => [stateRetriever: StateGetter<State>, stateMutator: Setter<State>|ActionCollectionResult<State>, metadataRetriever: Metadata];
|
|
243
315
|
|
|
244
|
-
|
|
245
|
-
|
|
316
|
+
// example:
|
|
317
|
+
const [getContacts, setContacts] = useContacts.stateControls();
|
|
246
318
|
|
|
247
|
-
|
|
248
|
-
isLoading: true,
|
|
249
|
-
filter: "",
|
|
250
|
-
items: [] as Contact[],
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
export const [contactsRetriever, contactsRetriever] =
|
|
254
|
-
useContacts.stateControls();
|
|
319
|
+
console.log(getContacts()); // prints the list of contacts
|
|
255
320
|
```
|
|
256
321
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
While **useContacts** will allow your components to subscribe to the custom hook, using the **contactsRetriever** method you will be able retrieve the current value of the state. This allows you to access the state whenever necessary, without being reactive to its changes. Let' see how:
|
|
322
|
+
**stateMutator** is particularly useful when you want to create components that have editing access to a specific store but don't necessarily need to reactively respond to state changes.
|
|
260
323
|
|
|
261
|
-
|
|
262
|
-
// To synchronously get the value of the state
|
|
263
|
-
const value = contactsRetriever();
|
|
324
|
+
Using the **stateRetriever** and the **stateMutator** allows you to retrieve the state when needed without establishing a reactive relationship with the state changes. This approach provides more flexibility and control over when and how components interact with the global state.
|
|
264
325
|
|
|
265
|
-
|
|
266
|
-
```
|
|
326
|
+
So, While **useContacts** will allow your components to subscribe to the custom hook, using the **contactsRetriever** method you will be able retrieve the current value of the state. This allows you to access the state whenever necessary, without being reactive to its changes and with the **contactsMutator** you now have the ability to modify the state without the need for subscription to the hook.
|
|
267
327
|
|
|
268
328
|
Additionally, to subscribe to state changes, you can pass a callback function as a parameter to the **stateRetriever**. This approach enables you to create a subscription group, allowing you to subscribe to either the entire state or a specific portion of it. When a callback function is provided to the **stateRetriever**, it will return a cleanup function instead of the state. This cleanup function can be used to unsubscribe or clean up the subscription when it is no longer needed.
|
|
269
329
|
|
|
@@ -288,19 +348,162 @@ const removeSubscriptionGroup = contactsRetriever<Subscribe>((subscribe) => {
|
|
|
288
348
|
|
|
289
349
|
That's great, isn't it? everything stays synchronized with the original state!!
|
|
290
350
|
|
|
291
|
-
|
|
351
|
+
## stateMutator
|
|
292
352
|
|
|
293
|
-
|
|
353
|
+
Let's add more actions to the state and explore how to use one action from inside another.
|
|
354
|
+
|
|
355
|
+
Here's an example of adding multiple actions to the state and utilizing one action within another:
|
|
294
356
|
|
|
295
357
|
```ts
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
358
|
+
import { createGlobalState } from "react-hooks-global-states";
|
|
359
|
+
|
|
360
|
+
export const useCount = createGlobalState(0, {
|
|
361
|
+
actions: {
|
|
362
|
+
log: (currentValue: string) => {
|
|
363
|
+
return ({ getState }: StoreTools<number>): void => {
|
|
364
|
+
console.log(`Current Value: ${getState()}`);
|
|
365
|
+
};
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
increase(value: number = 1) {
|
|
369
|
+
return ({ getState, setState, actions }: StoreTools<number>) => {
|
|
370
|
+
setState((count) => count + value);
|
|
371
|
+
|
|
372
|
+
actions.log(message);
|
|
373
|
+
};
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
decrease(value: number = 1) {
|
|
377
|
+
return ({ getState, setState, actions }: StoreTools<number>) => {
|
|
378
|
+
setState((count) => count - value);
|
|
379
|
+
|
|
380
|
+
actions.log(message);
|
|
381
|
+
};
|
|
382
|
+
},
|
|
383
|
+
} as const,
|
|
384
|
+
});
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Notice that the **StoreTools** will contain a reference to the generated actions API. From there, you'll be able to access all actions from inside another one... the **StoreTools** is generic and allow your to set an interface for getting the typing on the actions.
|
|
388
|
+
|
|
389
|
+
# Stateful Context with Actions
|
|
390
|
+
|
|
391
|
+
**The ultimate blend of flexibility and control in React state management!** You can now create an isolated global state within a React context, giving each consumer of the context provider a unique state instance. But that’s not all...
|
|
392
|
+
|
|
393
|
+
**Stateful Context with Actions** extends the powerful features of global hooks into the realm of React Context. By integrating global hooks within a context, you bring all the benefits of global state management—such as modularity, selectors, derived states, and actions—into a context-specific environment. This means each consumer of the context not only gets a unique state instance but also inherits all the advanced capabilities of global hooks.
|
|
394
|
+
|
|
395
|
+
## Creating a Stateful Context
|
|
396
|
+
|
|
397
|
+
Forget about the boilerplate of creating a context... with **createStatefulContext** it's straightforward and powerful. You can create a context and provider with one line of code.
|
|
398
|
+
|
|
399
|
+
```tsx
|
|
400
|
+
export const [useCounterContext, CounterProvider] = createStatefulContext(2);
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Then just wrap the components you need with the provider:
|
|
404
|
+
|
|
405
|
+
```tsx
|
|
406
|
+
<CounterProvider>
|
|
407
|
+
<MyComponent />
|
|
408
|
+
</CounterProvider>
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
And finally, access the context value with the generated custom hook:
|
|
412
|
+
|
|
413
|
+
```tsx
|
|
414
|
+
const MyComponent = () => {
|
|
415
|
+
const [useCounter] = useCounterContext();
|
|
416
|
+
|
|
417
|
+
// If the component needs to react to state changes, simply use the hook
|
|
418
|
+
const [count, setCount] = useCounter();
|
|
419
|
+
|
|
420
|
+
return <>{count}</>;
|
|
421
|
+
};
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
What’s the advantage of this, you might ask? Well, now you have all the capabilities of the global hooks within the isolated scope of the context. For example, you can choose whether or not to listen to changes in the state:
|
|
425
|
+
|
|
426
|
+
```tsx
|
|
427
|
+
const MyComponent = () => {
|
|
428
|
+
const [, , setCount] = useCounterContext();
|
|
429
|
+
|
|
430
|
+
// This component can access only the stateMutator of the state,
|
|
431
|
+
// and won't re-render if the counter changes
|
|
432
|
+
return <button onClick={() => setCount((count) => count + 1)}>Increase</button>;
|
|
433
|
+
};
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Now you have selectors—if the state changes, the component will only re-render if the selected portion of the state changes.
|
|
437
|
+
|
|
438
|
+
```tsx
|
|
439
|
+
const MyComponent = () => {
|
|
440
|
+
const [useCounter] = useCounterContext();
|
|
441
|
+
|
|
442
|
+
// Notice that we can select and derive values from the state
|
|
443
|
+
const [isEven, setCount] = useCounter((count) => count % 2 === 0);
|
|
444
|
+
|
|
445
|
+
useEffect(() => {
|
|
446
|
+
// Since the counter initially was 2 and now is 4, it’s still an even number.
|
|
447
|
+
// Because of this, the component will not re-render.
|
|
448
|
+
setCount(4);
|
|
449
|
+
}, []);
|
|
450
|
+
|
|
451
|
+
return <>{isEven ? "is even" : "is odd"}</>;
|
|
452
|
+
};
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**createStatefulContext** also allows you to add custom actions to control the manipulation of the state.
|
|
456
|
+
|
|
457
|
+
```tsx
|
|
458
|
+
import { createStatefulContext, StoreTools } from "react-global-state-hooks";
|
|
459
|
+
|
|
460
|
+
export const [useCounterContext, CounterProvider] = createStatefulContext(
|
|
461
|
+
{
|
|
462
|
+
count: 0,
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
actions: {
|
|
466
|
+
increase: (value: number = 1) => {
|
|
467
|
+
return ({ setState }) => {
|
|
468
|
+
setState((state) => ({
|
|
469
|
+
...state,
|
|
470
|
+
count: state.count + value,
|
|
471
|
+
}));
|
|
472
|
+
};
|
|
473
|
+
},
|
|
474
|
+
decrease: (value: number = 1) => {
|
|
475
|
+
return ({ setState }) => {
|
|
476
|
+
setState((state) => ({
|
|
477
|
+
...state,
|
|
478
|
+
count: state.count - value,
|
|
479
|
+
}));
|
|
480
|
+
};
|
|
481
|
+
},
|
|
482
|
+
} as const,
|
|
483
|
+
}
|
|
301
484
|
);
|
|
302
485
|
```
|
|
303
486
|
|
|
487
|
+
And just like with regular global hooks, now instead of a setState function, the hook will return the collection of actions:
|
|
488
|
+
|
|
489
|
+
```tsx
|
|
490
|
+
const MyComponent = () => {
|
|
491
|
+
const [, , actions] = useCounterContext();
|
|
492
|
+
|
|
493
|
+
return <button onClick={() => actions.increase(1)}>Increase</button>;
|
|
494
|
+
};
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
# Emitters
|
|
498
|
+
|
|
499
|
+
So, we have seen that we can subscribe a callback to state changes, create **selector hooks** from our global states. Guess what? We can also create derived **emitters** and subscribe callbacks to specific portions of the state. Let's review it:
|
|
500
|
+
|
|
501
|
+
```ts
|
|
502
|
+
const subscribeToFilter = createDerivateEmitter(contactsRetriever, ({ filter }) => ({
|
|
503
|
+
filter,
|
|
504
|
+
}));
|
|
505
|
+
```
|
|
506
|
+
|
|
304
507
|
Cool, it's basically the same, but instead of using the **hook** as a parameter, we just have to use the **stateRetriever** as a parameter, and that will make the magic.
|
|
305
508
|
|
|
306
509
|
Now we are able to add a callback that will be executed every time the state of the **filter** changes.
|
|
@@ -324,7 +527,7 @@ const removeFilterSubscription = subscribeToFilter<Subscribe>(
|
|
|
324
527
|
);
|
|
325
528
|
```
|
|
326
529
|
|
|
327
|
-
Also, of course, if you have an exceptional case where you want to
|
|
530
|
+
Also, of course, if you have an exceptional case where you want to derived/selected directly from the current **emitter**, you can add a **selector**. This allows you to fine-tune the emitted values based on your requirements
|
|
328
531
|
|
|
329
532
|
```ts
|
|
330
533
|
const removeFilterSubscription = subscribeToFilter<Subscribe>(
|
|
@@ -350,26 +553,20 @@ const removeFilterSubscription = subscribeToFilter<Subscribe>(
|
|
|
350
553
|
And guess what again? You can also derive emitters from derived emitters without any trouble at all! It works basically the same. Let's see an example:
|
|
351
554
|
|
|
352
555
|
```ts
|
|
353
|
-
const subscribeToItems = createDerivateEmitter(
|
|
354
|
-
contactsRetriever,
|
|
355
|
-
({ items }) => items
|
|
356
|
-
);
|
|
556
|
+
const subscribeToItems = createDerivateEmitter(contactsRetriever, ({ items }) => items);
|
|
357
557
|
|
|
358
|
-
const subscribeToItemsLength = createDerivateEmitter(
|
|
359
|
-
subscribeToItems,
|
|
360
|
-
(items) => items.length
|
|
361
|
-
);
|
|
558
|
+
const subscribeToItemsLength = createDerivateEmitter(subscribeToItems, (items) => items.length);
|
|
362
559
|
```
|
|
363
560
|
|
|
364
|
-
The examples may seem a little silly, but they allow you to see the incredible things you can accomplish with these **
|
|
561
|
+
The examples may seem a little silly, but they allow you to see the incredible things you can accomplish with these **derived states** and **emitters**. They open up a world of possibilities!
|
|
365
562
|
|
|
366
|
-
# Combining
|
|
563
|
+
# Combining stateRetriever
|
|
367
564
|
|
|
368
|
-
What if you have two states and you want to combine them? You may have already guessed it right? ... you can create combined **emitters** and **hooks** from the **
|
|
565
|
+
What if you have two states and you want to combine them? You may have already guessed it right? ... you can create combined **emitters** and **hooks** from the hook **stateRetriever**.
|
|
369
566
|
|
|
370
567
|
By utilizing the approach of combining **emitters** and **hooks**, you can effectively merge multiple states and make them shareable. This allows for better organization and simplifies the management of the combined states. You don't need to refactor everything; you just need to combine the **global state hooks** you already have. Let's see a simple example:
|
|
371
568
|
|
|
372
|
-
|
|
569
|
+
First we are gonna create a couple of **global states**, and extract the **stateRetriever**.
|
|
373
570
|
|
|
374
571
|
```ts
|
|
375
572
|
const useHook1 = createGlobalState({
|
|
@@ -384,13 +581,13 @@ const useHook2 = createGlobalState({
|
|
|
384
581
|
propD: 4,
|
|
385
582
|
});
|
|
386
583
|
|
|
387
|
-
const [stateRetriever2] = useHook2.stateControls();
|
|
584
|
+
const [, stateRetriever2] = useHook2.stateControls();
|
|
388
585
|
```
|
|
389
586
|
|
|
390
587
|
Okay, cool, the first state as **propA, propB** while the second one has **propC, propD**, let's combine them:
|
|
391
588
|
|
|
392
589
|
```ts
|
|
393
|
-
const [useCombinedHook,
|
|
590
|
+
const [useCombinedHook, combinedStateRetriever] = combineAsyncGetters(
|
|
394
591
|
{
|
|
395
592
|
selector: ([state1, state2]) => ({
|
|
396
593
|
...state1,
|
|
@@ -402,7 +599,7 @@ const [useCombinedHook, stateRetriever, dispose] = combineAsyncGetters(
|
|
|
402
599
|
);
|
|
403
600
|
```
|
|
404
601
|
|
|
405
|
-
Well, that's it! Now you have access to a **
|
|
602
|
+
Well, that's it! Now you have access to a **combinedStateRetriever** that will return the combined value of the two states. From this new **combinedStateRetriever**, you can retrieve the value or subscribe to its changes. Let'see:
|
|
406
603
|
|
|
407
604
|
```ts
|
|
408
605
|
const value = stateRetriever(); // { propA, propB, propC, propD }
|
|
@@ -417,8 +614,8 @@ const unsubscribeGroup = stateRetriever<Subscribe>((subscribe) => {
|
|
|
417
614
|
// the callback will only trigger if the result of the selector changes.
|
|
418
615
|
subscribe(
|
|
419
616
|
({ propA, propD }) => ({ propA, propD }),
|
|
420
|
-
(
|
|
421
|
-
console.log(
|
|
617
|
+
(derived) => {
|
|
618
|
+
console.log(derived); // { propA, propD }
|
|
422
619
|
}
|
|
423
620
|
);
|
|
424
621
|
});
|
|
@@ -440,22 +637,21 @@ Similar to your other **global state hooks**, **combined hooks** allow you to us
|
|
|
440
637
|
const [fragment] = useCombinedHook(({ propA, propD }) => ({ propA, propD }));
|
|
441
638
|
```
|
|
442
639
|
|
|
443
|
-
Lastly, you have the flexibility to continue combining
|
|
640
|
+
Lastly, you have the flexibility to continue combining stateRetrievers if desired. This means you can extend the functionality of combined hooks by adding more stateRetrievers to merge additional states. By combining stateRetrievers in this way, you can create a comprehensive and unified representation of the combined states within your application. This approach allows for modular and scalable state management, enabling you to efficiently handle complex state compositions.
|
|
444
641
|
|
|
445
642
|
Let's see an example:
|
|
446
643
|
|
|
447
644
|
```ts
|
|
448
|
-
const [useCombinedHook, combinedStateRetriever1
|
|
449
|
-
|
|
450
|
-
{
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
);
|
|
645
|
+
const [useCombinedHook, combinedStateRetriever1] = combineAsyncGetters(
|
|
646
|
+
{
|
|
647
|
+
selector: ([state1, state2]) => ({
|
|
648
|
+
...state1,
|
|
649
|
+
...state2,
|
|
650
|
+
}),
|
|
651
|
+
},
|
|
652
|
+
stateRetriever1,
|
|
653
|
+
stateRetriever2
|
|
654
|
+
);
|
|
459
655
|
|
|
460
656
|
const useHook3 = createGlobalState({
|
|
461
657
|
propE: 1,
|
|
@@ -466,13 +662,13 @@ const [stateRetriever3, stateMutator3] = useHook3.stateControls();
|
|
|
466
662
|
|
|
467
663
|
const useIsLoading = createGlobalState(false);
|
|
468
664
|
|
|
469
|
-
const [
|
|
665
|
+
const [isLoadingStateRetriever, isLoadingMutator] = useIsLoading.stateControls();
|
|
470
666
|
```
|
|
471
667
|
|
|
472
668
|
Once we created another peace of state, we can combine it with our other **global hooks** and **emitters**
|
|
473
669
|
|
|
474
670
|
```ts
|
|
475
|
-
const [useCombinedHook2,
|
|
671
|
+
const [useCombinedHook2, combinedStateRetriever2] = combineAsyncGetters(
|
|
476
672
|
{
|
|
477
673
|
selector: ([state1, state2, isLoading]) => ({
|
|
478
674
|
...state1,
|
|
@@ -482,7 +678,7 @@ const [useCombinedHook2, combinedGetter2, dispose2] = combineAsyncGetters(
|
|
|
482
678
|
},
|
|
483
679
|
combinedStateRetriever1,
|
|
484
680
|
stateRetriever3,
|
|
485
|
-
|
|
681
|
+
isLoadingStateRetriever
|
|
486
682
|
);
|
|
487
683
|
```
|
|
488
684
|
|
|
@@ -492,190 +688,6 @@ You have the freedom to combine as many global hooks as you wish. This means you
|
|
|
492
688
|
|
|
493
689
|
Please be aware that the third parameter is a **dispose callback**, which can be particularly useful in **high-order** functions when you want to release any resources associated with the hook. By invoking the dispose callback, the hook will no longer report any changes, ensuring that resources are properly cleaned up. This allows for efficient resource management and can be beneficial in scenarios where you need to handle resource cleanup or termination in a controlled manner.
|
|
494
690
|
|
|
495
|
-
## Setter
|
|
496
|
-
|
|
497
|
-
Similarly, the **contactsRetriever** method allows you to modify the state stored in **useContacts**. You can use this method to update the state with a new value or perform any necessary state mutations without the restrictions imposed by **hooks**.
|
|
498
|
-
|
|
499
|
-
These additional methods provide a more flexible and granular way to interact with the state managed by **useContacts**. You can retrieve and modify the state as needed, without establishing a subscription relationship or reactivity with the state changes.
|
|
500
|
-
|
|
501
|
-
Let's add more actions to the state and explore how to use one action from inside another.
|
|
502
|
-
|
|
503
|
-
Here's an example of adding multiple actions to the state and utilizing one action within another:
|
|
504
|
-
|
|
505
|
-
```ts
|
|
506
|
-
import { createGlobalState } from "react-native-global-state-hooks";
|
|
507
|
-
|
|
508
|
-
export const useCount = createGlobalState(0, {
|
|
509
|
-
actions: {
|
|
510
|
-
log: (currentValue: string) => {
|
|
511
|
-
return ({ getState }: StoreTools<number>): void => {
|
|
512
|
-
console.log(`Current Value: ${getState()}`);
|
|
513
|
-
};
|
|
514
|
-
},
|
|
515
|
-
|
|
516
|
-
increase(value: number = 1) {
|
|
517
|
-
return ({ getState, setState, actions }: StoreTools<number>) => {
|
|
518
|
-
setState((count) => count + value);
|
|
519
|
-
|
|
520
|
-
actions.log(message);
|
|
521
|
-
};
|
|
522
|
-
},
|
|
523
|
-
|
|
524
|
-
decrease(value: number = 1) {
|
|
525
|
-
return ({ getState, setState, actions }: StoreTools<number>) => {
|
|
526
|
-
setState((count) => count - value);
|
|
527
|
-
|
|
528
|
-
actions.log(message);
|
|
529
|
-
};
|
|
530
|
-
},
|
|
531
|
-
} as const,
|
|
532
|
-
});
|
|
533
|
-
```
|
|
534
|
-
|
|
535
|
-
Notice that the **StoreTools** will contain a reference to the generated actions API. From there, you'll be able to access all actions from inside another one... the **StoreTools** is generic and allow your to set an interface for getting the typing on the actions.
|
|
536
|
-
|
|
537
|
-
```ts
|
|
538
|
-
import { createGlobalState } from "react-native-global-state-hooks";
|
|
539
|
-
|
|
540
|
-
export const useCount = createGlobalState(0, {
|
|
541
|
-
actions: {
|
|
542
|
-
log: (currentValue: string) => {
|
|
543
|
-
return ({ getState }: StoreTools<number>): void => {
|
|
544
|
-
console.log(`Current Value: ${getState()}`);
|
|
545
|
-
};
|
|
546
|
-
},
|
|
547
|
-
|
|
548
|
-
increase(value: number = 1) {
|
|
549
|
-
return ({ getState, setState }: StoreTools<number>) => {
|
|
550
|
-
setState((count) => count + value);
|
|
551
|
-
|
|
552
|
-
$actions.log(message);
|
|
553
|
-
};
|
|
554
|
-
},
|
|
555
|
-
} as const,
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
export const [getCount, $actions] = useCount.stateControls();
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
In the example the hook will work the same and you'll have access to the correct typing.
|
|
562
|
-
|
|
563
|
-
# Stateful Context with Actions
|
|
564
|
-
|
|
565
|
-
**The ultimate blend of flexibility and control in React state management!** You can now create an isolated global state within a React context, giving each consumer of the context provider a unique state instance. But that’s not all...
|
|
566
|
-
|
|
567
|
-
**Stateful Context with Actions** extends the powerful features of global hooks into the realm of React Context. By integrating global hooks within a context, you bring all the benefits of global state management—such as modularity, selectors, derived states, and actions—into a context-specific environment. This means each consumer of the context not only gets a unique state instance but also inherits all the advanced capabilities of global hooks.
|
|
568
|
-
|
|
569
|
-
## Creating a Stateful Context
|
|
570
|
-
|
|
571
|
-
Forget about the boilerplate of creating a context... with **createStatefulContext** it's straightforward and powerful. You can create a context and provider with one line of code.
|
|
572
|
-
|
|
573
|
-
```tsx
|
|
574
|
-
export const [useCounterContext, CounterProvider] = createStatefulContext(2);
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
Then just wrap the components you need with the provider:
|
|
578
|
-
|
|
579
|
-
```tsx
|
|
580
|
-
<CounterProvider>
|
|
581
|
-
<MyComponent />
|
|
582
|
-
</CounterProvider>
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
And finally, access the context value with the generated custom hook:
|
|
586
|
-
|
|
587
|
-
```tsx
|
|
588
|
-
const MyComponent = () => {
|
|
589
|
-
const [useCounter] = useCounterContext();
|
|
590
|
-
|
|
591
|
-
// If the component needs to react to state changes, simply use the hook
|
|
592
|
-
const [count, setCount] = useCounter();
|
|
593
|
-
|
|
594
|
-
return <>{count}</>;
|
|
595
|
-
};
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
What’s the advantage of this, you might ask? Well, now you have all the capabilities of the global hooks within the isolated scope of the context. For example, you can choose whether or not to listen to changes in the state:
|
|
599
|
-
|
|
600
|
-
```tsx
|
|
601
|
-
const MyComponent = () => {
|
|
602
|
-
const [, , setCount] = useCounterContext();
|
|
603
|
-
|
|
604
|
-
// This component can access only the stateMutator of the state,
|
|
605
|
-
// and won't re-render if the counter changes
|
|
606
|
-
return (
|
|
607
|
-
<button onClick={() => setCount((count) => count + 1)}>Increase</button>
|
|
608
|
-
);
|
|
609
|
-
};
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
Now you have selectors—if the state changes, the component will only re-render if the selected portion of the state changes.
|
|
613
|
-
|
|
614
|
-
```tsx
|
|
615
|
-
const MyComponent = () => {
|
|
616
|
-
const [useCounter] = useCounterContext();
|
|
617
|
-
|
|
618
|
-
// Notice that we can select and derive values from the state
|
|
619
|
-
const [isEven, setCount] = useCounter((count) => count % 2 === 0);
|
|
620
|
-
|
|
621
|
-
useEffect(() => {
|
|
622
|
-
// Since the counter initially was 2 and now is 4, it’s still an even number.
|
|
623
|
-
// Because of this, the component will not re-render.
|
|
624
|
-
setCount(4);
|
|
625
|
-
}, []);
|
|
626
|
-
|
|
627
|
-
return <>{isEven ? "is even" : "is odd"}</>;
|
|
628
|
-
};
|
|
629
|
-
```
|
|
630
|
-
|
|
631
|
-
**createStatefulContext** also allows you to add custom actions to control the manipulation of the state.
|
|
632
|
-
|
|
633
|
-
```tsx
|
|
634
|
-
import { createStatefulContext, StoreTools } from "react-global-state-hooks";
|
|
635
|
-
|
|
636
|
-
type CounterState = {
|
|
637
|
-
count: number;
|
|
638
|
-
};
|
|
639
|
-
|
|
640
|
-
const initialState: CounterState = {
|
|
641
|
-
count: 0,
|
|
642
|
-
};
|
|
643
|
-
|
|
644
|
-
export const [useCounterContext, CounterProvider] = createStatefulContext(
|
|
645
|
-
initialState,
|
|
646
|
-
{
|
|
647
|
-
actions: {
|
|
648
|
-
increase: (value: number = 1) => {
|
|
649
|
-
return ({ setState }: StoreTools<CounterState>) => {
|
|
650
|
-
setState((state) => ({
|
|
651
|
-
...state,
|
|
652
|
-
count: state.count + value,
|
|
653
|
-
}));
|
|
654
|
-
};
|
|
655
|
-
},
|
|
656
|
-
decrease: (value: number = 1) => {
|
|
657
|
-
return ({ setState }: StoreTools<CounterState>) => {
|
|
658
|
-
setState((state) => ({
|
|
659
|
-
...state,
|
|
660
|
-
count: state.count - value,
|
|
661
|
-
}));
|
|
662
|
-
};
|
|
663
|
-
},
|
|
664
|
-
} as const,
|
|
665
|
-
}
|
|
666
|
-
);
|
|
667
|
-
```
|
|
668
|
-
|
|
669
|
-
And just like with regular global hooks, now instead of a setState function, the hook will return the collection of actions:
|
|
670
|
-
|
|
671
|
-
```tsx
|
|
672
|
-
const MyComponent = () => {
|
|
673
|
-
const [, , actions] = useCounterContext();
|
|
674
|
-
|
|
675
|
-
return <button onClick={() => actions.increase(1)}>Increase</button>;
|
|
676
|
-
};
|
|
677
|
-
```
|
|
678
|
-
|
|
679
691
|
# Extending Global Hooks
|
|
680
692
|
|
|
681
693
|
## `[IMPORTANT!]`: From version 6.0.0, you can continue creating your custom implementations or using your previous ones. However, now AsyncStorage is already integrated into the global hooks with @react-native-async-storage/async-storage. You simply need to add a key for the persistent storage, and that will do the trick.
|
|
@@ -700,7 +712,7 @@ const useCountPersisted = createGlobalState(1, {
|
|
|
700
712
|
const [count, setCount, { isAsyncStorageReady }] = useCountPersisted();
|
|
701
713
|
```
|
|
702
714
|
|
|
703
|
-
##### Now lets continue
|
|
715
|
+
##### Now lets continue analyzing how to create a custom GlobalStore!
|
|
704
716
|
|
|
705
717
|
Creating a global hook that connects to an asyncStorage is made incredibly easy with the **createCustomGlobalState** function.
|
|
706
718
|
|
|
@@ -842,17 +854,17 @@ onInit?: ({
|
|
|
842
854
|
/**
|
|
843
855
|
* @description - callback function called every time the state is changed
|
|
844
856
|
*/
|
|
845
|
-
onStateChanged?: (parameters:
|
|
857
|
+
onStateChanged?: (parameters: StoreTools<any, any> & StateChanges<unknown>) => void;
|
|
846
858
|
|
|
847
859
|
/**
|
|
848
860
|
* callback function called every time a component is subscribed to the store
|
|
849
861
|
*/
|
|
850
|
-
onSubscribed?: (parameters:
|
|
862
|
+
onSubscribed?: (parameters: StoreTools<any, any>) => void;
|
|
851
863
|
|
|
852
864
|
/**
|
|
853
865
|
* callback function called every time the state is about to change and it allows you to prevent the state change
|
|
854
866
|
*/
|
|
855
|
-
computePreventStateChange?: (parameters:
|
|
867
|
+
computePreventStateChange?: (parameters: StoreTools<any, any> & StateChanges<unknown>) => boolean;
|
|
856
868
|
```
|
|
857
869
|
|
|
858
870
|
You can pass this callbacks between on the second parameter of the builders like **createGlobalState**
|
|
@@ -886,9 +898,7 @@ export class GlobalStore<
|
|
|
886
898
|
asyncStorageKey?: string;
|
|
887
899
|
isAsyncStorageReady?: boolean;
|
|
888
900
|
} | null = null,
|
|
889
|
-
TStateSetter extends
|
|
890
|
-
| ActionCollectionConfig<TState, TMetadata>
|
|
891
|
-
| StateSetter<TState> = StateSetter<TState>
|
|
901
|
+
TStateSetter extends ActionCollectionConfig<TState, TMetadata> | StateSetter<TState> = StateSetter<TState>
|
|
892
902
|
> extends GlobalStoreAbstract<TState, TMetadata, TStateSetter> {
|
|
893
903
|
constructor(
|
|
894
904
|
state: TState,
|
|
@@ -936,10 +946,7 @@ export class GlobalStore<
|
|
|
936
946
|
setState(items, { forceUpdate: true });
|
|
937
947
|
};
|
|
938
948
|
|
|
939
|
-
protected onChange = ({
|
|
940
|
-
getMetadata,
|
|
941
|
-
getState,
|
|
942
|
-
}: StateChangesParam<TState, TMetadata, NonNullable<TStateSetter>>) => {
|
|
949
|
+
protected onChange = ({ getMetadata, getState }: StoreTools<any, any> & StateChanges<unknown>) => {
|
|
943
950
|
const asyncStorageKey = getMetadata()?.asyncStorageKey;
|
|
944
951
|
|
|
945
952
|
if (!asyncStorageKey) return;
|
|
@@ -959,9 +966,8 @@ Then, from an instance of the global store, you will be able to access the hooks
|
|
|
959
966
|
|
|
960
967
|
```ts
|
|
961
968
|
const storage = new GlobalStore(0, {
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
isAsyncStorageReady: false,
|
|
969
|
+
asyncStorage: {
|
|
970
|
+
key: "counter",
|
|
965
971
|
},
|
|
966
972
|
});
|
|
967
973
|
|