@lomray/react-mobx-manager 2.0.0-beta.10 → 2.0.0-beta.12
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 +14 -5
- package/lib/context.d.ts +1 -3
- package/lib/context.js +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/manager-stream.d.ts +29 -0
- package/lib/manager-stream.js +1 -0
- package/lib/manager.d.ts +1 -1
- package/lib/manager.js +1 -1
- package/lib/on-change-listener.d.ts +1 -1
- package/lib/storages/async-storage.d.ts +1 -1
- package/lib/storages/local-storage.d.ts +1 -1
- package/lib/suspense-query.d.ts +28 -6
- package/lib/suspense-query.js +1 -1
- package/lib/{types-9745a837.d.ts → types-8fe84e04.d.ts} +2 -2
- package/lib/wakeup.d.ts +1 -1
- package/lib/with-stores.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
<h1 align='center'>Mobx stores manager for React</h1>
|
|
6
6
|
|
|
7
7
|
- One way to escape state tree 🌲🌳🌴.
|
|
8
|
+
- Ready to use with Suspense.
|
|
8
9
|
- Manage your Mobx stores like a boss - debug like a hacker.
|
|
9
10
|
- Simple idea - simple implementation.
|
|
10
11
|
- Small package size.
|
|
@@ -52,6 +53,8 @@ The React-mobx-manager package is distributed using [npm](https://www.npmjs.com/
|
|
|
52
53
|
npm i --save @lomray/react-mobx-manager
|
|
53
54
|
```
|
|
54
55
|
|
|
56
|
+
__WARNING:__ this package use [@lomray/consistent-suspense](https://github.com/Lomray-Software/consistent-suspense) for generate stable id's inside Suspense.
|
|
57
|
+
|
|
55
58
|
**Optional:** Configure your bundler to keep classnames and function names in production OR use `id` for each store:
|
|
56
59
|
|
|
57
60
|
- **React:** (craco or webpack config, terser options)
|
|
@@ -77,24 +80,27 @@ Import `Manager, StoreManagerProvider` from `@lomray/react-mobx-manager` into yo
|
|
|
77
80
|
```typescript jsx
|
|
78
81
|
import React from 'react';
|
|
79
82
|
import ReactDOM from 'react-dom/client';
|
|
80
|
-
import '
|
|
83
|
+
import { ConsistentSuspenseProvider } from '@lomray/consistent-suspense';
|
|
81
84
|
import { Manager, StoreManagerProvider, MobxLocalStorage } from '@lomray/react-mobx-manager';
|
|
82
85
|
import App from './app';
|
|
83
86
|
import MyApiClient from './services/my-api-client';
|
|
87
|
+
import './index.css';
|
|
84
88
|
|
|
85
89
|
const apiClient = new MyApiClient();
|
|
86
90
|
const storeManager = new Manager({
|
|
87
91
|
storage: new MobxLocalStorage(), // optional: needs for persisting stores
|
|
88
|
-
storesParams: { apiClient }, // optional: we can provide our api client for access from the store
|
|
92
|
+
storesParams: { apiClient }, // optional: we can provide our api client for access from the each store
|
|
89
93
|
});
|
|
90
94
|
|
|
91
95
|
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
|
92
96
|
|
|
93
97
|
root.render(
|
|
94
98
|
<React.StrictMode>
|
|
95
|
-
<
|
|
96
|
-
<
|
|
97
|
-
|
|
99
|
+
<ConsistentSuspenseProvider> {/** required, see warning above **/}
|
|
100
|
+
<StoreManagerProvider storeManager={storeManager} shouldInit>
|
|
101
|
+
<App />
|
|
102
|
+
</StoreManagerProvider>
|
|
103
|
+
</ConsistentSuspenseProvider>
|
|
98
104
|
</React.StrictMode>,
|
|
99
105
|
);
|
|
100
106
|
```
|
|
@@ -468,6 +474,9 @@ Lifecycles:
|
|
|
468
474
|
- init
|
|
469
475
|
- onDestroy
|
|
470
476
|
|
|
477
|
+
## Demo
|
|
478
|
+
Explore [demo app](https://github.com/Lomray-Software/vite-template) to more understand.
|
|
479
|
+
|
|
471
480
|
## React Native debug plugin
|
|
472
481
|
For debug state, you can use [Reactotron debug plugin](https://github.com/Lomray-Software/reactotron-mobx-store-manager)
|
|
473
482
|
|
package/lib/context.d.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import { IConsistentSuspense } from '@lomray/consistent-suspense';
|
|
3
2
|
import React from 'react';
|
|
4
3
|
import { FC, ReactElement } from "react";
|
|
5
4
|
import Manager from "./manager.js";
|
|
6
|
-
import { TStores } from "./types-
|
|
5
|
+
import { TStores } from "./types-8fe84e04.js";
|
|
7
6
|
interface IStoreManagerProvider {
|
|
8
7
|
storeManager: Manager;
|
|
9
8
|
shouldInit?: boolean;
|
|
10
9
|
fallback?: ReactElement;
|
|
11
10
|
children?: React.ReactNode;
|
|
12
|
-
suspenseProvider?: Partial<IConsistentSuspense>;
|
|
13
11
|
}
|
|
14
12
|
interface IStoreManagerParentProvider {
|
|
15
13
|
parentId: string;
|
package/lib/context.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react");function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=t(e);const a=r.default.createContext({}),o=r.default.createContext("root"),n=({parentId:e,children:t,initStores:a})=>{const n=s();return a&&n.touchedStores(a),r.default.createElement(o.Provider,{value:e,children:t})},s=()=>e.useContext(a);exports.StoreManagerContext=a,exports.StoreManagerParentContext=o,exports.StoreManagerParentProvider=n,exports.StoreManagerProvider=({children:t,storeManager:o,fallback:s,shouldInit:u=!1})=>{const[l,c]=e.useState(!u);return e.useEffect((()=>{u&&o.init().then((()=>c(!0))).catch((e=>{console.error("Failed initialized store manager: ",e)}))}),[u,o]),r.default.createElement(a.Provider,{value:o},r.default.createElement(n,{parentId:"root"},l?t:s||t))},exports.useStoreManager=s,exports.useStoreManagerParent=()=>e.useContext(o);
|
package/lib/index.d.ts
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Manager from "./manager.js";
|
|
2
|
+
/**
|
|
3
|
+
* Stream mobx manager stores
|
|
4
|
+
*/
|
|
5
|
+
declare class ManagerStream {
|
|
6
|
+
/**
|
|
7
|
+
* Already pushed preamble
|
|
8
|
+
*/
|
|
9
|
+
protected isPreamblePushed: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Mobx store manager
|
|
12
|
+
*/
|
|
13
|
+
protected manager: Manager;
|
|
14
|
+
/**
|
|
15
|
+
* @constructor
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* @constructor
|
|
19
|
+
*/
|
|
20
|
+
constructor(manager: Manager);
|
|
21
|
+
/**
|
|
22
|
+
* Return script with suspense stores to push on stream
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Return script with suspense stores to push on stream
|
|
26
|
+
*/
|
|
27
|
+
take(suspenseId: string): string | void;
|
|
28
|
+
}
|
|
29
|
+
export { ManagerStream as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";module.exports=class{constructor(e){Object.defineProperty(this,"isPreamblePushed",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"manager",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.manager=e}take(e){const s=this.manager.getSuspenseRelations().get(e);if(!(null==s?void 0:s.size))return;const i=JSON.stringify(this.manager.toJSON([...s])),t=this.isPreamblePushed?"":"<script>!window.mbxM && (window.mbxM = []);<\/script>";return this.isPreamblePushed||(this.isPreamblePushed=!0),`${t}<script>window.mbxM.push(${i});<\/script>`}};
|
package/lib/manager.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import StoreStatus from "./store-status.js";
|
|
2
|
-
import { IConstructableStore, IManagerOptions, IManagerParams, IStorage, IStore, IStoreParams, TInitStore, TStoreDefinition, TStores } from "./types-
|
|
2
|
+
import { IConstructableStore, IManagerOptions, IManagerParams, IStorage, IStore, IStoreParams, TInitStore, TStoreDefinition, TStores } from "./types-8fe84e04.js";
|
|
3
3
|
/**
|
|
4
4
|
* Mobx stores manager
|
|
5
5
|
*/
|
package/lib/manager.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@lomray/event-manager"),t=require("mobx"),s=require("./events.js"),
|
|
1
|
+
"use strict";var e=require("@lomray/event-manager"),t=require("mobx"),s=require("./events.js"),r=require("./on-change-listener.js"),o=require("./store-status.js"),i=require("./wakeup.js");function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var a=n(e);class l{constructor({initState:e,storesParams:t,storage:s,options:r}={}){if(Object.defineProperty(this,"stores",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"storesRelations",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"initState",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"storage",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"persistData",{enumerable:!0,configurable:!0,writable:!0,value:{}}),Object.defineProperty(this,"storesParams",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"options",{enumerable:!0,configurable:!0,writable:!0,value:{shouldDisablePersist:!1,shouldRemoveInitState:!0}}),Object.defineProperty(this,"suspenseRelations",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"pushInitState",{enumerable:!0,configurable:!0,writable:!0,value:(e={})=>{for(const[t,s]of Object.entries(e))this.initState[t]=s}}),this.initState=e||{},this.storesParams=t||{},this.storage=s,Object.assign(this.options,r||{}),l.instance=this,"undefined"!=typeof window){const e=window.mbxM;window.mbxM={push:this.pushInitState},(Array.isArray(e)?e:[]).forEach(this.pushInitState)}}async init(){return this.storage&&(this.persistData=await this.storage.get()||{}),this}static get(){if(!l.instance)throw new Error("Store manager is not initialized.");return l.instance}getStores(){return this.stores}getStoresRelations(){return this.storesRelations}getSuspenseRelations(){return this.suspenseRelations}static getPersistedStoresIds(){return l.persistedStores}getStoreId(e,t={}){const{id:s,contextId:r,key:o}=t;if(s)return s;if(e.libStoreId)return e.libStoreId;let i=e.name||e.constructor.name;return e.isSingleton?i:(i=`${i}--${r}`,o?`${i}--${o}`:i)}getStore(e,t={}){const s=this.getStoreId(e,t);return this.stores.has(s)?this.stores.get(s):e.isSingleton?this.createStore(e,{id:s,contextId:"singleton",parentId:"root",suspenseId:"",componentName:"root-app",componentProps:{}}):this.lookupStore(s,t)}lookupStore(e,t){var s,r;const{contextId:o,parentId:i}=t,n=null===(s=e.split("--"))||void 0===s?void 0:s[0],{ids:a,parentId:l}=null!==(r=this.storesRelations.get(o))&&void 0!==r?r:{ids:new Set,parentId:i},u=[...a].filter((e=>e.startsWith(`${n}--`)));if(1===u.length)return this.stores.get(u[0]);if(u.length>1)console.error("Parent context has multiple stores with the same id, please pass key to getStore function.");else if(l&&"root"!==l)return this.lookupStore(e,{contextId:l})}createStore(e,t){const{id:r,contextId:i,parentId:n,suspenseId:l,componentName:u,componentProps:d}=t;if(this.stores.has(r))return this.stores.get(r);const h=new e({...this.storesParams,storeManager:this,getStore:(e,t={contextId:i,parentId:n})=>this.getStore(e,t),componentProps:d});return h.libStoreId=r,h.isSingleton=e.isSingleton,h.libStoreContextId=e.isSingleton?"singleton":i,h.libStoreParentId=e.isSingleton||!n||n===i?"root":n,h.libStoreSuspenseId=l,h.libStoreComponentName=u,this.setStoreStatus(h,e.isSingleton?o.inUse:o.init),this.prepareStore(h),a.default.publish(s.CREATE_STORE,{store:e}),h}createStores(e,t,s,r,o,i={}){return e.reduce(((e,[n,a])=>{const[l,u]="store"in a?[a.store,a.id]:[a,this.getStoreId(a,{key:n,contextId:s})];return{...e,[n]:this.createStore(l,{id:u,contextId:s,parentId:t,suspenseId:r,componentName:o,componentProps:i})}}),{})}prepareStore(e){var t,r,o;const i=e.libStoreId,n=e.libStoreContextId,u=e.libStoreSuspenseId,d=this.initState[i],h=this.persistData[i];if(this.stores.has(i))return;if(d&&Object.assign(e,d),"wakeup"in e&&l.persistedStores.has(i)&&(null===(t=e.wakeup)||void 0===t||t.call(e,{initState:d,persistedState:h})),l.persistedStores.has(i)&&"addOnChangeListener"in e){const t=null===(r=e.onDestroy)||void 0===r?void 0:r.bind(e),s=e.addOnChangeListener(e,this);e.onDestroy=()=>{null==s||s(),null==t||t()}}null===(o=e.init)||void 0===o||o.call(e),this.storesRelations.has(n)||this.storesRelations.set(n,{ids:new Set,parentId:e.libStoreParentId&&e.libStoreParentId!==n?e.libStoreParentId:"root",componentName:e.libStoreComponentName}),this.suspenseRelations.has(u)||this.suspenseRelations.set(u,new Set);const{ids:c}=this.storesRelations.get(n);this.stores.set(i,e),c.add(i),this.suspenseRelations.get(u).add(i),a.default.publish(s.ADD_STORE,{store:e})}removeStore(e){var t,r,o;const i=e.libStoreId,n=e.libStoreSuspenseId,{ids:l}=null!==(t=this.storesRelations.get(e.libStoreContextId))&&void 0!==t?t:{ids:new Set};this.stores.has(i)&&(this.stores.delete(i),l.delete(i),n&&(null===(r=this.suspenseRelations.get(n))||void 0===r?void 0:r.has(i))&&this.suspenseRelations.get(n).delete(i),l.size||this.storesRelations.delete(e.libStoreContextId),"onDestroy"in e&&(null===(o=e.onDestroy)||void 0===o||o.call(e)),a.default.publish(s.DELETE_STORE,{store:e}))}mountStores(e){const{shouldRemoveInitState:t}=this.options;return Object.values(e).forEach((e=>{const r=e.libStoreId;t&&this.initState[r]&&delete this.initState[r],this.setStoreStatus(e,o.inUse),a.default.publish(s.MOUNT_STORE,{store:e})})),()=>{Object.values(e).forEach((e=>{e.isSingleton||(this.setStoreStatus(e,o.unused),a.default.publish(s.UNMOUNT_STORE,{store:e}))}))}}touchedStores(e){Object.values(e).forEach((e=>{e.libStoreStatus!==o.init||e.isSingleton||this.setStoreStatus(e,o.touched)}))}setStoreStatus(e,t){const{destroyTimers:{init:s=500,touched:r=1e4,unused:i=1e3}={}}=this.options;e.libStoreStatus=t,clearTimeout(e.libDestroyTimer);let n=0;switch(t){case o.init:n=s;break;case o.touched:n=r;break;case o.unused:n=i}n&&(e.libDestroyTimer=setTimeout((()=>this.removeStore(e)),n))}toJSON(e){var t,s,r;const o={},i=null!==(t=null==e?void 0:e.reduce(((e,t)=>(this.stores.has(t)&&e.set(t,this.stores.get(t)),e)),new Map))&&void 0!==t?t:this.stores;for(const[e,t]of i.entries())o[e]=null!==(r=null===(s=t.toJSON)||void 0===s?void 0:s.call(t))&&void 0!==r?r:l.getObservableProps(t);return o}toPersistedJSON(){var e,t;const s={};for(const r of l.persistedStores){const o=this.stores.get(r);o&&(s[r]=null!==(t=null===(e=o.toJSON)||void 0===e?void 0:e.call(o))&&void 0!==t?t:l.getObservableProps(o))}return s}static getObservableProps(e){const s=t.toJS(e);return Object.entries(s).reduce(((s,[r,o])=>({...s,...t.isObservableProp(e,r)?{[r]:o}:{}})),{})}static persistStore(e,t){return l.persistedStores.has(t)?(console.warn(`Duplicate serializable store key: ${t}`),e):(l.persistedStores.add(t),e.libStoreId=t,"wakeup"in e.prototype||(e.prototype.wakeup=i.bind(e)),"addOnChangeListener"in e.prototype||(e.prototype.addOnChangeListener=r),e)}}Object.defineProperty(l,"persistedStores",{enumerable:!0,configurable:!0,writable:!0,value:new Set}),module.exports=l;
|
package/lib/suspense-query.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TInitStore } from "./types-
|
|
1
|
+
import { TInitStore } from "./types-8fe84e04.js";
|
|
2
2
|
interface IPromise<TReturn> extends Promise<TReturn> {
|
|
3
3
|
status?: 'fulfilled' | 'pending' | 'rejected';
|
|
4
4
|
value?: TReturn;
|
|
@@ -6,6 +6,7 @@ interface IPromise<TReturn> extends Promise<TReturn> {
|
|
|
6
6
|
}
|
|
7
7
|
interface ISuspenseQueryParams {
|
|
8
8
|
fieldName?: string;
|
|
9
|
+
errorFields?: string[];
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
12
|
* Run request and cache promise
|
|
@@ -16,10 +17,6 @@ declare class SuspenseQuery {
|
|
|
16
17
|
* @private
|
|
17
18
|
*/
|
|
18
19
|
protected promise: Promise<any> | undefined;
|
|
19
|
-
/**
|
|
20
|
-
* @private
|
|
21
|
-
*/
|
|
22
|
-
protected error?: Error;
|
|
23
20
|
/**
|
|
24
21
|
* Target store
|
|
25
22
|
* @private
|
|
@@ -35,7 +32,32 @@ declare class SuspenseQuery {
|
|
|
35
32
|
/**
|
|
36
33
|
* @constructor
|
|
37
34
|
*/
|
|
38
|
-
constructor(store: TInitStore, { fieldName,
|
|
35
|
+
constructor(store: TInitStore, { fieldName, errorFields }?: ISuspenseQueryParams);
|
|
36
|
+
/**
|
|
37
|
+
* Error to json
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Error to json
|
|
41
|
+
*/
|
|
42
|
+
protected errorJson(e: any): void;
|
|
43
|
+
/**
|
|
44
|
+
* Assign custom error fields to error
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* Assign custom error fields to error
|
|
48
|
+
*/
|
|
49
|
+
protected jsonToError(e: Error, values: Record<string, any>): Error;
|
|
50
|
+
/**
|
|
51
|
+
* Detect if suspense is restored from server side:
|
|
52
|
+
* - throw error if exist
|
|
53
|
+
* - skip run suspense if already completed
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* Detect if suspense is restored from server side:
|
|
57
|
+
* - throw error if exist
|
|
58
|
+
* - skip run suspense if already completed
|
|
59
|
+
*/
|
|
60
|
+
protected isComplete(): boolean;
|
|
39
61
|
/**
|
|
40
62
|
* Run request
|
|
41
63
|
* Save request resolve status
|
package/lib/suspense-query.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("mobx");class r{constructor(t,{fieldName:i="
|
|
1
|
+
"use strict";var e=require("mobx");class r{constructor(t,{fieldName:i="sR",errorFields:s=["name","message"]}={}){var o;Object.defineProperty(this,"promise",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"store",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"params",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"query",{enumerable:!0,configurable:!0,writable:!0,value:t=>{const{fieldName:i}=this.params;if(!this.isComplete())return this.promise||(this.promise=t(),this.promise.then((()=>{e.runInAction((()=>{this.store[i]=!0}))}),(r=>{e.runInAction((()=>{this.errorJson(r),this.store[i]=r}))}))),r.run(this.promise)}}),this.store=t,this.params={fieldName:i,errorFields:s};const a=null===(o=t.init)||void 0===o?void 0:o.bind(t);t.init=()=>{this.isComplete(),null==a||a()},e.extendObservable(t,{[i]:!1},{[i]:e.observable})}errorJson(e){e.toJSON=()=>this.params.errorFields.reduce(((r,t)=>({...r,[t]:null==e?void 0:e[t]})),{})}jsonToError(e,r){return this.params.errorFields.forEach((t=>{e[t]=null==r?void 0:r[t]})),e}isComplete(){var e;const r=this.store[this.params.fieldName];if("boolean"!==typeof r)throw this.jsonToError(new Error(null!==(e=null==r?void 0:r.message)&&void 0!==e?e:null==r?void 0:r.name),r);return!0===r}}Object.defineProperty(r,"run",{enumerable:!0,configurable:!0,writable:!0,value:e=>{if(e){switch(e.status){case"fulfilled":return e.value;case"pending":throw e;case"rejected":throw e.reason;default:e.status="pending",e.then((r=>{e.status="fulfilled",e.value=r}),(r=>{e.status="rejected",e.reason=r}))}throw e}}}),module.exports=r;
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import Manager from "./manager.js";
|
|
3
3
|
import StoreStatus from "./store-status.js";
|
|
4
4
|
interface IWindowManager {
|
|
5
|
-
|
|
5
|
+
push: (state: Record<string, any>) => void;
|
|
6
6
|
}
|
|
7
7
|
declare global {
|
|
8
8
|
interface Window {
|
|
9
|
-
|
|
9
|
+
mbxM: Record<string, any>[] | IWindowManager;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
interface IConstructorParams<TProps = Record<string, any>> {
|
package/lib/wakeup.d.ts
CHANGED
package/lib/with-stores.d.ts
CHANGED