@lomray/react-mobx-manager 4.2.1 → 4.3.0-beta.1
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 +15 -528
- package/index.d.ts +1 -0
- package/index.js +1 -1
- package/make-fetching.d.ts +11 -7
- package/make-fetching.js +1 -1
- package/make-fetching.js.map +1 -1
- package/manager.d.ts +14 -0
- package/manager.js +1 -1
- package/manager.js.map +1 -1
- package/package.json +23 -21
- package/parent-store.d.ts +9 -0
- package/parent-store.js +2 -0
- package/parent-store.js.map +1 -0
- package/plugins/dev-extension/hmr/adapters.d.ts +9 -0
- package/plugins/dev-extension/hmr/adapters.js +2 -0
- package/plugins/dev-extension/hmr/adapters.js.map +1 -0
- package/plugins/dev-extension/hmr/index.d.ts +3 -0
- package/plugins/dev-extension/hmr/index.js +2 -0
- package/plugins/dev-extension/hmr/index.js.map +1 -0
- package/plugins/dev-extension/hmr/service.d.ts +71 -0
- package/plugins/dev-extension/hmr/service.js +2 -0
- package/plugins/dev-extension/hmr/service.js.map +1 -0
- package/plugins/dev-extension/hmr/types.d.ts +14 -0
- package/plugins/dev-extension/hmr/types.js +2 -0
- package/plugins/dev-extension/hmr/types.js.map +1 -0
- package/storages/combined-storage.d.ts +1 -1
- package/storages/combined-storage.js +1 -1
- package/storages/combined-storage.js.map +1 -1
- package/storages/cookie-storage.js +1 -1
- package/storages/cookie-storage.js.map +1 -1
- package/storages/local-storage.js +1 -1
- package/storages/local-storage.js.map +1 -1
- package/suspense-query.js +1 -1
- package/suspense-query.js.map +1 -1
- package/types.d.ts +2 -1
- package/with-stores.js +1 -1
- package/with-stores.js.map +1 -1
package/README.md
CHANGED
|
@@ -1,553 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
# React MobX Manager
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
<img src="./logo.png" alt="Mobx stores manager logo" width="250" height="253">
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
MobX store manager for React with relative, parent and global stores.
|
|
8
|
+
|
|
9
|
+
It is built for apps that want explicit store ownership, SSR support, persistence, lifecycle cleanup and development tooling without forcing everything into one global state tree.
|
|
10
|
+
|
|
11
|
+
## Why use it
|
|
8
12
|
|
|
9
13
|
- One way to escape state tree 🌲🌳🌴.
|
|
10
14
|
- Ready to use with Suspense.
|
|
11
15
|
- Support SSR.
|
|
12
16
|
- Support render to stream.
|
|
13
|
-
-
|
|
14
|
-
-
|
|
17
|
+
- Relative stores for component-owned state
|
|
18
|
+
- Parent stores for subtree reuse
|
|
19
|
+
- Global stores for app-wide state
|
|
15
20
|
- Small package size.
|
|
16
21
|
- Support code splitting out of the box.
|
|
17
22
|
- Access stores from other stores.
|
|
18
23
|
- Can be a replacement for react context.
|
|
24
|
+
- Persistence support
|
|
25
|
+
- Vite plugin support
|
|
26
|
+
- Best-effort HMR
|
|
19
27
|
- And many other nice things 😎
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
<img src="https://sonarcloud.io/api/project_badges/measure?project=Lomray-Software_react-mobx-manager&metric=reliability_rating" alt="reliability">
|
|
23
|
-
<img src="https://sonarcloud.io/api/project_badges/measure?project=Lomray-Software_react-mobx-manager&metric=security_rating" alt="Security Rating">
|
|
24
|
-
<img src="https://sonarcloud.io/api/project_badges/measure?project=Lomray-Software_react-mobx-manager&metric=sqale_rating" alt="Maintainability Rating">
|
|
25
|
-
<img src="https://sonarcloud.io/api/project_badges/measure?project=Lomray-Software_react-mobx-manager&metric=vulnerabilities" alt="Vulnerabilities">
|
|
26
|
-
<img src="https://sonarcloud.io/api/project_badges/measure?project=Lomray-Software_react-mobx-manager&metric=bugs" alt="Bugs">
|
|
27
|
-
<img src="https://sonarcloud.io/api/project_badges/measure?project=Lomray-Software_react-mobx-manager&metric=ncloc" alt="Lines of Code">
|
|
28
|
-
<img src="https://sonarcloud.io/api/project_badges/measure?project=Lomray-Software_react-mobx-manager&metric=coverage" alt="code coverage">
|
|
29
|
-
<img src="https://img.shields.io/bundlephobia/minzip/@lomray/react-mobx-manager" alt="size">
|
|
30
|
-
<img src="https://img.shields.io/npm/l/@lomray/react-mobx-manager" alt="size">
|
|
31
|
-
<img src="https://img.shields.io/npm/v/@lomray/react-mobx-manager?label=semantic%20release&logo=semantic-release" alt="semantic version">
|
|
32
|
-
</p>
|
|
33
|
-
|
|
34
|
-
## Table of contents
|
|
35
|
-
|
|
36
|
-
- [Getting started](#getting-started)
|
|
37
|
-
- [Usage](#usage)
|
|
38
|
-
- [Support SSR](#support-ssr)
|
|
39
|
-
- [Important Tips](#important-tips)
|
|
40
|
-
- [Documentation](#documentation)
|
|
41
|
-
- [Manager](#manager)
|
|
42
|
-
- [withStores](#withstores)
|
|
43
|
-
- [StoreManagerProvider](#storemanagerprovider)
|
|
44
|
-
- [useStoreManagerContext](#usestoremanager)
|
|
45
|
-
- [useStoreManagerParentContext](#usestoremanagerparent)
|
|
46
|
-
- [Store](#store)
|
|
47
|
-
- [Example](#demo)
|
|
48
|
-
- [React Native Debug Plugin](#react-native-debug-plugin)
|
|
49
|
-
- [Bugs and feature requests](#bugs-and-feature-requests)
|
|
50
|
-
- [License](#license)
|
|
51
|
-
|
|
52
|
-
## Getting started
|
|
53
|
-
|
|
54
|
-
The React-mobx-manager package is distributed using [npm](https://www.npmjs.com/), the node package manager.
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
npm i --save @lomray/react-mobx-manager @lomray/consistent-suspense
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
__NOTE:__ this package use [@lomray/consistent-suspense](https://github.com/Lomray-Software/consistent-suspense) for generate stable id's inside Suspense.
|
|
29
|
+
## Install
|
|
61
30
|
|
|
62
|
-
__Choose one of store id generating strategy (1 or 2 or 3)__:
|
|
63
|
-
|
|
64
|
-
1. Configure your bundler to keep classnames and function names. Store id will be generated from class names (chose unique class names).
|
|
65
|
-
- **React:** (craco or webpack config, terser options)
|
|
66
31
|
```bash
|
|
67
|
-
|
|
68
|
-
terserOptions.keep_fnames = true;
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
- **React Native:** (metro bundler config: metro.config.js)
|
|
72
|
-
```js
|
|
73
|
-
module.exports = {
|
|
74
|
-
transformer: {
|
|
75
|
-
minifierConfig: {
|
|
76
|
-
keep_classnames: true,
|
|
77
|
-
keep_fnames: true,
|
|
78
|
-
},
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
2. Define `id` for each store.
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
import { makeObservable } from "mobx";
|
|
86
|
-
|
|
87
|
-
class MyStore {
|
|
88
|
-
/**
|
|
89
|
-
* Define unique store id
|
|
90
|
-
*/
|
|
91
|
-
static id = 'Unique-store-id';
|
|
92
|
-
|
|
93
|
-
constructor() {
|
|
94
|
-
makeObservable(this, {})
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
3. Use `Vite plugins`.
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
import { defineConfig } from 'vite';
|
|
102
|
-
import react from '@vitejs/plugin-react';
|
|
103
|
-
import MobxManager from '@lomray/react-mobx-manager/plugins/vite/index';
|
|
104
|
-
|
|
105
|
-
// https://vitejs.dev/config/
|
|
106
|
-
export default defineConfig({
|
|
107
|
-
/**
|
|
108
|
-
* Store id's will be generated automatically, just chill
|
|
109
|
-
*/
|
|
110
|
-
plugins: [react(), MobxManager()]
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Detect mobx store:
|
|
115
|
-
- by makeObservable or makeAutoObservable
|
|
116
|
-
- by @mobx-store jsdoc before class
|
|
117
|
-
*/
|
|
32
|
+
npm i @lomray/react-mobx-manager @lomray/consistent-suspense
|
|
118
33
|
```
|
|
119
34
|
|
|
120
|
-
## Usage
|
|
121
|
-
|
|
122
|
-
Import `Manager, StoreManagerProvider` from `@lomray/react-mobx-manager` into your index file and wrap `<App/>` with `<StoreManagerProvider/>`
|
|
123
|
-
|
|
124
|
-
```typescript jsx
|
|
125
|
-
import React from 'react';
|
|
126
|
-
import ReactDOM from 'react-dom/client';
|
|
127
|
-
import { ConsistentSuspenseProvider } from '@lomray/consistent-suspense';
|
|
128
|
-
import { Manager, StoreManagerProvider, MobxLocalStorage } from '@lomray/react-mobx-manager';
|
|
129
|
-
import App from './app';
|
|
130
|
-
import MyApiClient from './services/my-api-client';
|
|
131
|
-
import './index.css';
|
|
132
|
-
|
|
133
|
-
const apiClient = new MyApiClient();
|
|
134
|
-
const storeManager = new Manager({
|
|
135
|
-
storage: new MobxLocalStorage(), // optional: needs for persisting stores
|
|
136
|
-
storesParams: { apiClient }, // optional: we can provide our api client for access from the each store
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
|
140
|
-
|
|
141
|
-
root.render(
|
|
142
|
-
<React.StrictMode>
|
|
143
|
-
<ConsistentSuspenseProvider> {/** required **/}
|
|
144
|
-
<StoreManagerProvider storeManager={storeManager} shouldInit>
|
|
145
|
-
<App />
|
|
146
|
-
</StoreManagerProvider>
|
|
147
|
-
</ConsistentSuspenseProvider>
|
|
148
|
-
</React.StrictMode>,
|
|
149
|
-
);
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
Connect mobx store to the manager, and you're good to go!
|
|
153
|
-
|
|
154
|
-
```typescript
|
|
155
|
-
import { withStores, Manager } from '@lomray/react-mobx-manager';
|
|
156
|
-
import { makeObservable, observable, action } from 'mobx';
|
|
157
|
-
import type { IConstructorParams, ClassReturnType } from '@lomray/react-mobx-manager';
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Mobx user store
|
|
161
|
-
*
|
|
162
|
-
* Usually store like that are related to the global store,
|
|
163
|
-
* because they store information about the current user,
|
|
164
|
-
* which may be needed in different places of the application.
|
|
165
|
-
*
|
|
166
|
-
* You may also want to save the state of the store, for example,
|
|
167
|
-
* to local storage, so that it can be restored after page reload,
|
|
168
|
-
* in this case, just export wrap export with 'persist':
|
|
169
|
-
* export default Manager.persistStore(UserStore, 'user');
|
|
170
|
-
*/
|
|
171
|
-
class UserStore {
|
|
172
|
-
/**
|
|
173
|
-
* Required only if we don't configure our bundler to keep classnames and function names
|
|
174
|
-
* Default: current class name
|
|
175
|
-
*/
|
|
176
|
-
static id = 'user';
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* You can also enable behavior for global application stores
|
|
180
|
-
* Default: false
|
|
181
|
-
*/
|
|
182
|
-
static isGlobal = true;
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Our state
|
|
186
|
-
*/
|
|
187
|
-
public name = 'Matthew'
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Our API client
|
|
191
|
-
*/
|
|
192
|
-
private apiClient: MyApiClient;
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* @constructor
|
|
196
|
-
*/
|
|
197
|
-
constructor({ getStore, apiClient }: IConstructorParams) {
|
|
198
|
-
this.apiClient = apiClient;
|
|
199
|
-
// if we need, we can get a global store or store from the parent context
|
|
200
|
-
// this.otherStore = getStore(SomeOtherStore);
|
|
201
|
-
|
|
202
|
-
makeObservable(this, {
|
|
203
|
-
name: observable,
|
|
204
|
-
setName: action.bound,
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Set user name
|
|
210
|
-
*/
|
|
211
|
-
public setName(name: string): void {
|
|
212
|
-
this.name = name;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Example async
|
|
217
|
-
* Call this func from component
|
|
218
|
-
*/
|
|
219
|
-
public getNameFromApi = async (userId: number) => {
|
|
220
|
-
const name = await this.apiClient.fetchName(userId);
|
|
221
|
-
|
|
222
|
-
this.setName(name);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Define stores for component
|
|
228
|
-
*/
|
|
229
|
-
const stores = {
|
|
230
|
-
userStore: UserStore
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
// support typescript
|
|
234
|
-
type TProps = StoresType <typeof stores>;
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* User component
|
|
238
|
-
*/
|
|
239
|
-
const User: FC<TProps> = ({ userStore: { name } }) => {
|
|
240
|
-
return (
|
|
241
|
-
<div>{name}</div>
|
|
242
|
-
)
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Connect stores to component
|
|
247
|
-
*/
|
|
248
|
-
export default withStores(User, stores);
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
[See app example](https://github.com/Lomray-Software/vite-template) for a better understanding.
|
|
252
|
-
|
|
253
|
-
## Support SSR
|
|
254
|
-
Does this library support SSR? Short answer - yes, but we need some steps to prepare our framework.
|
|
255
|
-
- Look at [Vite demo app](https://github.com/Lomray-Software/vite-template) for a better understanding.
|
|
256
|
-
- Look at [After.js (razzle) based project](https://github.com/Lomray-Software/microservices-dashboard/blob/staging/src/pages/user/index.tsx#L82) for a better understanding.
|
|
257
|
-
- Look at [NextJS example](https://github.com/Lomray-Software/nextjs-mobx-store-manager-example) for a better understanding (needs writing a wrapper).
|
|
258
|
-
|
|
259
|
-
## Important Tips
|
|
260
|
-
- Create **global** store only for e.g: application settings, logged user, theme, etc.
|
|
261
|
-
- To get started, stick to the concept: Store for Component. Don't connect (through withStores) not global store to several components.
|
|
262
|
-
|
|
263
35
|
## Documentation
|
|
264
36
|
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
import { Manager, MobxLocalStorage, MobxAsyncStorage } from '@lomray/react-mobx-manager';
|
|
268
|
-
// import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
269
|
-
|
|
270
|
-
// Params
|
|
271
|
-
const storeManager = new Manager({
|
|
272
|
-
/**
|
|
273
|
-
* Optional: needs for persisting stores when you use Manager.persistStore
|
|
274
|
-
* Available: MobxLocalStorage and MobxAsyncStorage
|
|
275
|
-
* Default: none
|
|
276
|
-
*/
|
|
277
|
-
storage: new MobxLocalStorage(), // React
|
|
278
|
-
// storage: new MobxAsyncStorage(AsyncStorage), // React Native
|
|
279
|
-
// storage: new CombinedStorage({ local: MobxAsyncStorage, cookie: CookieStorage }), // Define multiple storages
|
|
280
|
-
/**
|
|
281
|
-
* Optional: provide some params for access from store constructor
|
|
282
|
-
* E.g. we can provide our api client for access from the store
|
|
283
|
-
* Default: {}
|
|
284
|
-
*/
|
|
285
|
-
storesParams: { apiClient },
|
|
286
|
-
/**
|
|
287
|
-
* Initial stores state.
|
|
288
|
-
* E.g. in SSR case, restore client state from a server
|
|
289
|
-
* Default: {}
|
|
290
|
-
*/
|
|
291
|
-
initState: { storeId: { param: 'test' } },
|
|
292
|
-
/**
|
|
293
|
-
* Additional manager options
|
|
294
|
-
*/
|
|
295
|
-
options: {
|
|
296
|
-
/**
|
|
297
|
-
* Disable persisting stores
|
|
298
|
-
* E.g., it should be 'true' on a server-side (SSR)
|
|
299
|
-
* Default: false
|
|
300
|
-
*/
|
|
301
|
-
shouldDisablePersist: false,
|
|
302
|
-
/**
|
|
303
|
-
* Remove the initial store state after initialization
|
|
304
|
-
* Default: true
|
|
305
|
-
*/
|
|
306
|
-
shouldRemoveInitState: true,
|
|
307
|
-
/**
|
|
308
|
-
* Configure store destroy timers
|
|
309
|
-
*/
|
|
310
|
-
destroyTimers: {
|
|
311
|
-
init: 500,
|
|
312
|
-
touched: 10000, // NOTE: set to max request timeout
|
|
313
|
-
unused: 1000,
|
|
314
|
-
},
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
// Methods
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Optional: Call this method to load persisting data from persist storage
|
|
322
|
-
* E.g., you may want manually to do this before the app render
|
|
323
|
-
* Default: StoreManagerProvider does this automatically with 'shoudInit' prop
|
|
324
|
-
*/
|
|
325
|
-
await storeManager.init();
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Get all-created stores
|
|
329
|
-
*/
|
|
330
|
-
const managerStores = storeManager.getStores();
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Get specific store
|
|
334
|
-
*/
|
|
335
|
-
const store = storeManager.getStore(SomeGlobalStore);
|
|
336
|
-
const store2 = storeManager.getStore(SomeStore, { contextId: 'necessary-context-id' });
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Get stores context's and relations
|
|
340
|
-
*/
|
|
341
|
-
const relations = storeManager.getStoresRelations();
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Manually create stores for component
|
|
345
|
-
* NOTE: 'withStores' wrapper use this method, probably you won't need it
|
|
346
|
-
* WARNING: Avoid using this method directly, it may cause unexpected behavior
|
|
347
|
-
*/
|
|
348
|
-
const stores = storeManager.createStores(['someStore', MyStore], 'parent-id', 'context-id', 'suspense-id', 'HomePage', { componentProp: 'test' });
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Mount/Unmount simple stores to component
|
|
352
|
-
* WARNING: Avoid using this method directly, it may cause unexpected behavior
|
|
353
|
-
*/
|
|
354
|
-
const unmount = storeManager.mountStores(stores);
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Get all-stores state
|
|
358
|
-
*/
|
|
359
|
-
const storesState = storeManager.toJSON();
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Get all persisted store's state
|
|
363
|
-
*/
|
|
364
|
-
const persistedStoresState = storeManager.toPersistedJSON();
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Get only persisted stores id's
|
|
368
|
-
*/
|
|
369
|
-
const persistedIds = Manager.getPersistedStoresIds();
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Get store observable props
|
|
373
|
-
*/
|
|
374
|
-
const observableProps = Manager.getObservableProps(store);
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Static method for access to manager from anywhere
|
|
378
|
-
* NOTE: Be careful with this, especially with SSR on server-side
|
|
379
|
-
*/
|
|
380
|
-
const manager = Manager.get();
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Enable persisting state for store
|
|
384
|
-
*/
|
|
385
|
-
const storeClass = Manager.persistStore(class MyStore {}, 'my-store');
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Choose storage and attributes
|
|
389
|
-
*/
|
|
390
|
-
const storeClass2 = Manager.persistStore(class MyStore {}, 'my-store', {
|
|
391
|
-
attributes: {
|
|
392
|
-
local: ['someProp'], // thees attributes will be stored in local storage
|
|
393
|
-
cookie: ['specificProp'], // thees attributes will be stored in cookie storage
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
### withStores
|
|
399
|
-
```typescript
|
|
400
|
-
import { withStores } from '@lomray/react-mobx-manager';
|
|
401
|
-
|
|
402
|
-
const stores = {
|
|
403
|
-
myStore: MyStore,
|
|
404
|
-
anotherStore: AnotherStore,
|
|
405
|
-
// assign static id to future store
|
|
406
|
-
demoStore: { store: SomeStore, id: 'my-id' },
|
|
407
|
-
// get parent store, do this only inside children components
|
|
408
|
-
parentStore: { store: SomeParentStore, isParent: true },
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* Create and connect 'stores' to component with custom context id
|
|
413
|
-
* NOTE: In most cases, you don't need to pass a third argument (contextId).
|
|
414
|
-
*/
|
|
415
|
-
withStores(Component, stores, { customContextId: 'optional-context-id' });
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
### StoreManagerProvider
|
|
419
|
-
```typescript jsx
|
|
420
|
-
import { StoreManagerProvider } from '@lomray/react-mobx-manager';
|
|
421
|
-
|
|
422
|
-
/**
|
|
423
|
-
* Wrap your application for a pass-down store manager, context id, and init persisted state
|
|
424
|
-
*
|
|
425
|
-
* shouldInit - default: false, enable initialize peristed state
|
|
426
|
-
* fallback - show loader while the manager has initialized
|
|
427
|
-
*/
|
|
428
|
-
<StoreManagerProvider storeManager={storeManager} shouldInit fallback={<Loader />}>
|
|
429
|
-
{/* your components */}
|
|
430
|
-
</StoreManagerProvider>
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
### useStoreManager
|
|
434
|
-
```typescript jsx
|
|
435
|
-
import { useStoreManager } from '@lomray/react-mobx-manager';
|
|
436
|
-
|
|
437
|
-
const MyComponent: FC = () => {
|
|
438
|
-
/**
|
|
439
|
-
* Get store manager inside your function component
|
|
440
|
-
*/
|
|
441
|
-
const storeManager = useStoreManager();
|
|
442
|
-
}
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
### useStoreManagerParent
|
|
446
|
-
```typescript jsx
|
|
447
|
-
import { useStoreManagerParent } from '@lomray/react-mobx-manager';
|
|
448
|
-
|
|
449
|
-
const MyComponent: FC = () => {
|
|
450
|
-
/**
|
|
451
|
-
* Get parent context id
|
|
452
|
-
*/
|
|
453
|
-
const { parentId } = useStoreManagerParent();
|
|
454
|
-
}
|
|
455
|
-
```
|
|
456
|
-
|
|
457
|
-
### Store
|
|
458
|
-
|
|
459
|
-
```typescript
|
|
460
|
-
import { makeObservable, observable, action } from 'mobx';
|
|
461
|
-
|
|
462
|
-
class MyStore {
|
|
463
|
-
/**
|
|
464
|
-
* Required only if we don't configure our bundler to keep classnames and function names
|
|
465
|
-
* Default: current class name
|
|
466
|
-
*/
|
|
467
|
-
static id = 'user';
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* You can also enable behavior for global application stores
|
|
471
|
-
* Default: false
|
|
472
|
-
*/
|
|
473
|
-
static isGlobal = true;
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* Store observable state
|
|
477
|
-
*/
|
|
478
|
-
public state = {
|
|
479
|
-
name: 'Matthew',
|
|
480
|
-
username: 'meow',
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* @private
|
|
485
|
-
*/
|
|
486
|
-
private readonly someParentStore: ClassReturnType<typeof SomeParentStore>;
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* @constructor
|
|
490
|
-
*
|
|
491
|
-
* getStore - get parent store or global store
|
|
492
|
-
* storeManager - access to store manager
|
|
493
|
-
* apiClient - your custom param, see 'storesParams' in Manager
|
|
494
|
-
*/
|
|
495
|
-
constructor({ getStore, storeManager, apiClient, componentProps }: IConstructorParams) {
|
|
496
|
-
this.apiClient = apiClient;
|
|
497
|
-
this.someParentStore = getStore(SomeParentStore);
|
|
498
|
-
|
|
499
|
-
// In case when store is't global you can get access to component props
|
|
500
|
-
console.log(componentProps);
|
|
501
|
-
|
|
502
|
-
makeObservable(this, {
|
|
503
|
-
state: observable,
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
/**
|
|
508
|
-
* Define this method if you want to do something after initialize the store
|
|
509
|
-
* State restored, store ready for usage
|
|
510
|
-
* Optional.
|
|
511
|
-
* @private
|
|
512
|
-
*/
|
|
513
|
-
private init(): void {
|
|
514
|
-
// do something
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* Define this method if you want to do something when a component with this store is unmount
|
|
519
|
-
* @private
|
|
520
|
-
*/
|
|
521
|
-
private onDestroy(): void {
|
|
522
|
-
// do something
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Custom method for return store state
|
|
527
|
-
* Optional.
|
|
528
|
-
* Default: @see Manager.toJSON
|
|
529
|
-
*/
|
|
530
|
-
public toJSON(): Record<string, any> {
|
|
531
|
-
return { state: { username: this.state.username } };
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
Lifecycles:
|
|
537
|
-
- constructor
|
|
538
|
-
- wakeup (restore state from persisted store)
|
|
539
|
-
- init
|
|
540
|
-
- onDestroy
|
|
541
|
-
|
|
542
|
-
## Demo
|
|
543
|
-
Explore [demo app](https://github.com/Lomray-Software/vite-template) to more understand.
|
|
544
|
-
|
|
545
|
-
## React Native debug plugin
|
|
546
|
-
For debug state, you can use [Reactotron debug plugin](https://github.com/Lomray-Software/reactotron-mobx-store-manager)
|
|
547
|
-
|
|
548
|
-
## Bugs and feature requests
|
|
549
|
-
|
|
550
|
-
Bug or a feature request, [please open a new issue](https://github.com/Lomray-Software/react-mobx-manager/issues/new).
|
|
37
|
+
Full documentation lives in [here](https://lomray-software.github.io/react-mobx-manager/)
|
|
551
38
|
|
|
552
39
|
## License
|
|
553
40
|
Made with 💚
|
package/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { default as Manager } from "./manager.js";
|
|
|
4
4
|
export { default as onChangeListener } from "./on-change-listener.js";
|
|
5
5
|
export { default as wakeup } from "./wakeup.js";
|
|
6
6
|
export { default as withStores } from "./with-stores.js";
|
|
7
|
+
export { default as parentStore } from "./parent-store.js";
|
|
7
8
|
export * from "./make-exported.js";
|
|
8
9
|
export * from "./make-fetching.js";
|
|
9
10
|
export { default as Events } from "./events.js";
|
package/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export{StoreManagerContext,StoreManagerParentContext,StoreManagerParentProvider,StoreManagerProvider,useStoreManager,useStoreManagerParent}from"./context.js";export{default as Manager}from"./manager.js";export{default as onChangeListener}from"./on-change-listener.js";export{default as wakeup}from"./wakeup.js";export{default as withStores}from"./with-stores.js";export{isPropExcludedFromExport,isPropObservableExported,isPropSimpleExported,makeExported}from"./make-exported.js";import"mobx";export{default as Events}from"./events.js";export{default as Logger}from"./logger.js";
|
|
1
|
+
export{StoreManagerContext,StoreManagerParentContext,StoreManagerParentProvider,StoreManagerProvider,useStoreManager,useStoreManagerParent}from"./context.js";export{default as Manager}from"./manager.js";export{default as onChangeListener}from"./on-change-listener.js";export{default as wakeup}from"./wakeup.js";export{default as withStores}from"./with-stores.js";export{default as parentStore}from"./parent-store.js";export{isPropExcludedFromExport,isPropObservableExported,isPropSimpleExported,makeExported}from"./make-exported.js";import"mobx";export{default as Events}from"./events.js";export{default as Logger}from"./logger.js";
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/make-fetching.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
type AnyFn = (...args: any[]) => any;
|
|
2
|
+
type MethodKeys<T> = {
|
|
3
|
+
[K in keyof T]-?: T[K] extends AnyFn ? K : never;
|
|
4
|
+
}[keyof T];
|
|
5
|
+
type BooleanKeys<T> = {
|
|
6
|
+
[K in keyof T]-?: T[K] extends boolean ? K : never;
|
|
7
|
+
}[keyof T];
|
|
8
|
+
type StrictParams<T> = Partial<Record<MethodKeys<T>, BooleanKeys<T>>>;
|
|
9
|
+
type UnsafeParams = Record<string, string>;
|
|
10
|
+
declare function makeFetching<T extends Record<any, any>>(instance: T, params: StrictParams<T>, hasLock?: boolean): void;
|
|
11
|
+
declare function makeFetching<T extends Record<any, any>>(instance: T, params: UnsafeParams, hasLock?: boolean): void;
|
|
8
12
|
export { makeFetching as default };
|
package/make-fetching.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{runInAction as t}from"mobx";
|
|
1
|
+
import{runInAction as t}from"mobx";function o(o,e={},n=!1){Object.entries(e).forEach(([e,r])=>{const f=o[e];let a=0;const c=e=>{t(()=>{o[r]=e})},i=()=>{a=Math.max(a-1,0),0===a&&c(!1)};o[e]=(...t)=>{if(n&&o[r])return;a+=1,1===a&&c(!0);const e=f(...t);return"object"==typeof e&&e.finally?e.finally(()=>{i()}):i(),e}})}export{o as default};
|
|
2
2
|
//# sourceMappingURL=make-fetching.js.map
|
package/make-fetching.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"make-fetching.js","sources":["../src/make-fetching.ts"],"sourcesContent":["import { runInAction } from 'mobx';\n\ntype
|
|
1
|
+
{"version":3,"file":"make-fetching.js","sources":["../src/make-fetching.ts"],"sourcesContent":["import { runInAction } from 'mobx';\n\ntype AnyFn = (...args: any[]) => any;\n\ntype MethodKeys<T> = {\n [K in keyof T]-?: T[K] extends AnyFn ? K : never;\n}[keyof T];\n\ntype BooleanKeys<T> = {\n [K in keyof T]-?: T[K] extends boolean ? K : never;\n}[keyof T];\n\ntype StrictParams<T> = Partial<Record<MethodKeys<T>, BooleanKeys<T>>>;\ntype UnsafeParams = Record<string, string>;\n\nfunction makeFetching<T extends Record<any, any>>(\n instance: T,\n params: StrictParams<T>,\n hasLock?: boolean,\n): void;\nfunction makeFetching<T extends Record<any, any>>(\n instance: T,\n params: UnsafeParams,\n hasLock?: boolean,\n): void;\n\nfunction makeFetching<T extends Record<any, any>>(\n instance: T,\n params: StrictParams<T> | UnsafeParams = {},\n hasLock = false,\n): void {\n Object.entries(params).forEach(([funcName, propName]) => {\n const callback = instance[funcName] as (...arg: any[]) => any;\n let inFlight = 0;\n const setValue = (value: boolean): void => {\n runInAction(() => {\n // @ts-expect-error not necessary\n instance[propName] = value;\n });\n };\n const increment = (): void => {\n inFlight += 1;\n\n if (inFlight === 1) {\n setValue(true);\n }\n };\n const decrement = (): void => {\n inFlight = Math.max(inFlight - 1, 0);\n\n if (inFlight === 0) {\n setValue(false);\n }\n };\n\n // @ts-expect-error not necessary\n instance[funcName] = (...args: any[]) => {\n if (hasLock && instance[propName]) {\n return;\n }\n\n increment();\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n const result = callback(...args);\n\n if (typeof result === 'object' && result.finally) {\n result.finally(() => {\n decrement();\n });\n } else {\n decrement();\n }\n\n return result;\n };\n });\n}\n\nexport default makeFetching;\n"],"names":["makeFetching","instance","params","hasLock","Object","entries","forEach","funcName","propName","callback","inFlight","setValue","value","runInAction","decrement","Math","max","args","result","finally"],"mappings":"mCA0BA,SAASA,EACPC,EACAC,EAAyC,CAAA,EACzCC,GAAU,GAEVC,OAAOC,QAAQH,GAAQI,QAAQ,EAAEC,EAAUC,MACzC,MAAMC,EAAWR,EAASM,GAC1B,IAAIG,EAAW,EACf,MAAMC,EAAYC,IAChBC,EAAY,KAEVZ,EAASO,GAAYI,KAUnBE,EAAY,KAChBJ,EAAWK,KAAKC,IAAIN,EAAW,EAAG,GAEjB,IAAbA,GACFC,GAAS,IAKbV,EAASM,GAAY,IAAIU,KACvB,GAAId,GAAWF,EAASO,GACtB,OAjBFE,GAAY,EAEK,IAAbA,GACFC,GAAS,GAoBX,MAAMO,EAAST,KAAYQ,GAU3B,MARsB,iBAAXC,GAAuBA,EAAOC,QACvCD,EAAOC,QAAQ,KACbL,MAGFA,IAGKI,IAGb"}
|
package/manager.d.ts
CHANGED
|
@@ -165,6 +165,13 @@ declare class Manager {
|
|
|
165
165
|
* Delete relation context id
|
|
166
166
|
*/
|
|
167
167
|
protected removeRelationContext(contextId: string): void;
|
|
168
|
+
/**
|
|
169
|
+
* Append callback to store destroy lifecycle
|
|
170
|
+
*/
|
|
171
|
+
/**
|
|
172
|
+
* Append callback to store destroy lifecycle
|
|
173
|
+
*/
|
|
174
|
+
protected appendDestroyCallback(store: TStores[string], callback?: () => void): void;
|
|
168
175
|
/**
|
|
169
176
|
* Prepare store before usage
|
|
170
177
|
*/
|
|
@@ -190,6 +197,13 @@ declare class Manager {
|
|
|
190
197
|
* NOTE: use only inside withStores wrapper
|
|
191
198
|
*/
|
|
192
199
|
mountStores(contextId: string, { globalStores, relativeStores }: Partial<IGroupedStores>): () => void;
|
|
200
|
+
/**
|
|
201
|
+
* Destroy manager stores and detach internal relations
|
|
202
|
+
*/
|
|
203
|
+
/**
|
|
204
|
+
* Destroy manager stores and detach internal relations
|
|
205
|
+
*/
|
|
206
|
+
destroy(): void;
|
|
193
207
|
/**
|
|
194
208
|
* Change the stores status to touched
|
|
195
209
|
*/
|