as-model 0.3.2 → 0.3.3
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 +558 -558
- package/index.d.ts +12 -15
- package/package.json +68 -68
package/README.md
CHANGED
|
@@ -1,558 +1,558 @@
|
|
|
1
|
-
[![npm][npm-image]][npm-url]
|
|
2
|
-
[![NPM downloads][npm-downloads-image]][npm-url]
|
|
3
|
-
[![standard][standard-image]][standard-url]
|
|
4
|
-
|
|
5
|
-
[npm-image]: https://img.shields.io/npm/v/as-model.svg?style=flat-square
|
|
6
|
-
[npm-url]: https://www.npmjs.com/package/as-model
|
|
7
|
-
[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square
|
|
8
|
-
[standard-url]: http://npm.im/standard
|
|
9
|
-
[npm-downloads-image]: https://img.shields.io/npm/dm/as-model.svg?style=flat-square
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# as-model
|
|
13
|
-
|
|
14
|
-
This is a simple state management library with model coding style for javascript/typescript.
|
|
15
|
-
|
|
16
|
-
## Code first
|
|
17
|
-
|
|
18
|
-
Create a model function:
|
|
19
|
-
|
|
20
|
-
```js
|
|
21
|
-
// model.js
|
|
22
|
-
// A parameter for model state.
|
|
23
|
-
export function counting(state){
|
|
24
|
-
// Define instance object for outside usage.
|
|
25
|
-
return {
|
|
26
|
-
// Define properties for instance.
|
|
27
|
-
count: state,
|
|
28
|
-
symbol: !state? '': (state > 0? '+' : '-'),
|
|
29
|
-
// Create action methods for changing state.
|
|
30
|
-
increase:()=> state + 1,
|
|
31
|
-
decrease:()=> state - 1,
|
|
32
|
-
add(...additions){
|
|
33
|
-
return additions.reduce((result, current)=>{
|
|
34
|
-
return result + current;
|
|
35
|
-
}, state);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Create store:
|
|
42
|
-
|
|
43
|
-
```js
|
|
44
|
-
// store.js
|
|
45
|
-
import {counting} from './model';
|
|
46
|
-
import {createStore} from 'as-model';
|
|
47
|
-
|
|
48
|
-
// Create and initialize a model store.
|
|
49
|
-
const store = createStore(counting, 0);
|
|
50
|
-
// Get instance and call action methods to change state.
|
|
51
|
-
store.getInstance().increase();
|
|
52
|
-
// Get new properties from instance.
|
|
53
|
-
console.log(store.getInstance().count); // 1
|
|
54
|
-
store.getInstance().add(2,3);
|
|
55
|
-
console.log(store.getInstance().count); // 6
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Create multiple stores:
|
|
59
|
-
|
|
60
|
-
```js
|
|
61
|
-
import {counting} from './model';
|
|
62
|
-
import {createKey, createStores} from 'as-model';
|
|
63
|
-
|
|
64
|
-
// Create model key with initial state.
|
|
65
|
-
const countingKey0 = createKey(counting, 0);
|
|
66
|
-
const countingKey1 = createKey(counting, 1);
|
|
67
|
-
|
|
68
|
-
// Use model keys as templates to create multiple stores.
|
|
69
|
-
const stores = createStores(countingKey0, countingKey1);
|
|
70
|
-
// Find store by model key
|
|
71
|
-
const store0 = stores.find(countingKey0);
|
|
72
|
-
store0?.getInstance().increase();
|
|
73
|
-
console.log(store0?.getInstance().count); // 1
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
Model key is a template for creating multiple stores, and it is also an identifier to find the right store from multiple stores.
|
|
77
|
-
|
|
78
|
-
Use **model** API to create store or key.
|
|
79
|
-
|
|
80
|
-
```js
|
|
81
|
-
import {counting} from './model';
|
|
82
|
-
import {model} from 'as-model';
|
|
83
|
-
|
|
84
|
-
const store = model(counting).createStore(0);
|
|
85
|
-
const key = model(counting).createKey(0);
|
|
86
|
-
......
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
In typescript develop environment, `model` API can do a type check for making sure every model action method returns a correct type.
|
|
90
|
-
|
|
91
|
-
```js
|
|
92
|
-
// ts
|
|
93
|
-
import {model} from 'as-model';
|
|
94
|
-
|
|
95
|
-
// The model api ensures every action method returns a same type value with model state.
|
|
96
|
-
const counting = model((state: number)=>{
|
|
97
|
-
return {
|
|
98
|
-
count: state,
|
|
99
|
-
increase:()=>state + 1 + '', // type error, should be number, but returns string.
|
|
100
|
-
decrease:()=>state - 1,
|
|
101
|
-
add(...additions: number[]){
|
|
102
|
-
return additions.reduce((result, current)=>{
|
|
103
|
-
return result + current;
|
|
104
|
-
}, state);
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
const store = counting.createStore(0);
|
|
110
|
-
const key = counting.createKey(0);
|
|
111
|
-
......
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Subscribe store
|
|
115
|
-
|
|
116
|
-
```js
|
|
117
|
-
import {counting} from './model';
|
|
118
|
-
import {model} from 'as-model';
|
|
119
|
-
|
|
120
|
-
const store = model(counting).createStore(0);
|
|
121
|
-
const {getInstance} = store;
|
|
122
|
-
// Subscribe the state changes.
|
|
123
|
-
const unsubscribe = store.subscribe((action)=>{
|
|
124
|
-
console.log(store.getInstance());
|
|
125
|
-
});
|
|
126
|
-
getInstance().increase(); // output: {count: 1}
|
|
127
|
-
// Destroy subscription.
|
|
128
|
-
unsubscribe();
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
Want to use async operations?
|
|
132
|
-
|
|
133
|
-
```js
|
|
134
|
-
import {counting} from './model';
|
|
135
|
-
import {model, createSelector} from 'as-model';
|
|
136
|
-
|
|
137
|
-
const store = model(counting).select((getInstance)=>{
|
|
138
|
-
const instance = getInstance();
|
|
139
|
-
return {
|
|
140
|
-
...instance,
|
|
141
|
-
async delayIncrease(){
|
|
142
|
-
const ok = await new Promise((resolve)=>{
|
|
143
|
-
setTimeout(()=>{
|
|
144
|
-
resolve(true);
|
|
145
|
-
},200);
|
|
146
|
-
});
|
|
147
|
-
if(ok){
|
|
148
|
-
getInstance().increase();
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}).createStore(0);
|
|
153
|
-
|
|
154
|
-
const {subscribe, select} = createSelector(store);
|
|
155
|
-
const unsubscribe = subscribe();
|
|
156
|
-
// When use select with no parameter,
|
|
157
|
-
// select method finds default selector for reproducing result
|
|
158
|
-
const {delayIncrease} = select();
|
|
159
|
-
await delayIncrease();
|
|
160
|
-
select().count // 1
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
Subscribe store in react hooks:
|
|
164
|
-
|
|
165
|
-
```js
|
|
166
|
-
import {model, createStores} from 'as-model';
|
|
167
|
-
import {
|
|
168
|
-
createContext,
|
|
169
|
-
useRef,
|
|
170
|
-
useState,
|
|
171
|
-
useEffect,
|
|
172
|
-
useContext
|
|
173
|
-
} from 'react';
|
|
174
|
-
|
|
175
|
-
// Local state management
|
|
176
|
-
function useModel(modelFn, defaultState){
|
|
177
|
-
// Use ref to persist the store object.
|
|
178
|
-
const storeRef = useRef(model(modelFn).createStore(defaultState));
|
|
179
|
-
const store = storeRef.current;
|
|
180
|
-
// Set store instance as an initial state for useState.
|
|
181
|
-
const [state, setState] = useState(store.getInstance());
|
|
182
|
-
|
|
183
|
-
useEffect(()=>{
|
|
184
|
-
// Subscribe the state changes.
|
|
185
|
-
const unsubscribe = store.subscribe((action)=>{
|
|
186
|
-
setState(store.getInstance());
|
|
187
|
-
});
|
|
188
|
-
// Destroy subscription when component unmounts.
|
|
189
|
-
return unsubscribe;
|
|
190
|
-
}, []);
|
|
191
|
-
|
|
192
|
-
return state;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function App(){
|
|
196
|
-
const {
|
|
197
|
-
count,
|
|
198
|
-
increase
|
|
199
|
-
} = useModel(counting, 0);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// global static state management
|
|
203
|
-
function useModelStore(store){
|
|
204
|
-
const [state, setState] = useState(store.getInstance());
|
|
205
|
-
|
|
206
|
-
useEffect(()=>{
|
|
207
|
-
const unsubscribe = store.subscribe((action)=>{
|
|
208
|
-
setState(store.getInstance());
|
|
209
|
-
});
|
|
210
|
-
return unsubscribe;
|
|
211
|
-
}, []);
|
|
212
|
-
|
|
213
|
-
return state;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const store = model(counting).createStore({state: 0});
|
|
217
|
-
|
|
218
|
-
function App(){
|
|
219
|
-
const {
|
|
220
|
-
count,
|
|
221
|
-
increase
|
|
222
|
-
} = useModelStore(store);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// global dynamic state management
|
|
226
|
-
const ModelContext = createContext(null);
|
|
227
|
-
|
|
228
|
-
function create(...keys){
|
|
229
|
-
return {
|
|
230
|
-
provide(Component){
|
|
231
|
-
return function Provider(props){
|
|
232
|
-
// Create and persist multiple stores in Component, that makes different elements from this Component carry different stores.
|
|
233
|
-
const storesRef = useRef(createStores(...keys));
|
|
234
|
-
const stores = storesRef.current;
|
|
235
|
-
// Use Context to provide multiple stores to all the children.
|
|
236
|
-
return (
|
|
237
|
-
<ModelContext.Provider value={stores}>
|
|
238
|
-
<Component {...props} />
|
|
239
|
-
</ModelContext.Provider>
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function useModelKey(key){
|
|
247
|
-
const stores = useContext(ModelContext);
|
|
248
|
-
if(stores==null){
|
|
249
|
-
throw new Error('ModelContext is not provided');
|
|
250
|
-
}
|
|
251
|
-
// Use model key to find the right store.
|
|
252
|
-
const store = stores.find(key);
|
|
253
|
-
if(store==null){
|
|
254
|
-
throw new Error('Can not find store by model key');
|
|
255
|
-
}
|
|
256
|
-
const [state, setState] = useState(store.getInstance());
|
|
257
|
-
|
|
258
|
-
useEffect(()=>{
|
|
259
|
-
const unsubscribe = store.subscribe((action)=>{
|
|
260
|
-
setState(store.getInstance());
|
|
261
|
-
});
|
|
262
|
-
return unsubscribe;
|
|
263
|
-
}, []);
|
|
264
|
-
|
|
265
|
-
return state;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const countingKey = model(counting).createKey(0);
|
|
269
|
-
|
|
270
|
-
const App = create(countingKey).provide(function App(){
|
|
271
|
-
const {
|
|
272
|
-
count,
|
|
273
|
-
increase
|
|
274
|
-
} = useModelKey(countingKey);
|
|
275
|
-
});
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
## Install
|
|
279
|
-
|
|
280
|
-
```
|
|
281
|
-
npm install as-model
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
## Simplify API
|
|
285
|
-
|
|
286
|
-
### createStore
|
|
287
|
-
|
|
288
|
-
```js
|
|
289
|
-
function createStore(modelFnOrKey, initialState?):store
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
#### parameters
|
|
293
|
-
|
|
294
|
-
* modelFnOrKey - a model function accepts a state parameter and returns an object with action methods, or a model key of model function.
|
|
295
|
-
* initialState - the initial state of the model.
|
|
296
|
-
|
|
297
|
-
#### return
|
|
298
|
-
|
|
299
|
-
A store object with model key and methods. The store object has `getInstance` method to get the instance of the model; `subscribe` method to subscribe the state changes; `update` method to update the store with new model function and initial state; `destroy` method to destroy the store.
|
|
300
|
-
|
|
301
|
-
**store** structure:
|
|
302
|
-
|
|
303
|
-
```js
|
|
304
|
-
{
|
|
305
|
-
getInstance: ()=>instance,
|
|
306
|
-
subscribe: (listener)=>unsubscribe,
|
|
307
|
-
key: modelKey,
|
|
308
|
-
destroy: ()=>void,
|
|
309
|
-
update: (
|
|
310
|
-
data:{
|
|
311
|
-
model?:modelFn,
|
|
312
|
-
key?: modelKey,
|
|
313
|
-
initialState?: any
|
|
314
|
-
state?: any;
|
|
315
|
-
}
|
|
316
|
-
)=>void,
|
|
317
|
-
}
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
### createKey
|
|
321
|
-
|
|
322
|
-
```js
|
|
323
|
-
function createKey(modelFn, initialState?):key
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
#### parameters
|
|
327
|
-
|
|
328
|
-
* modelFn - a model function accepts a state parameter and returns an object with action methods.
|
|
329
|
-
* initialState - the initial state of the model.
|
|
330
|
-
|
|
331
|
-
#### return
|
|
332
|
-
|
|
333
|
-
A model key function with `createStore` method to create a store with the model key.
|
|
334
|
-
|
|
335
|
-
**key** structure:
|
|
336
|
-
|
|
337
|
-
```js
|
|
338
|
-
{
|
|
339
|
-
createStore: (initialState?)=>Store
|
|
340
|
-
}
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
### createStores
|
|
344
|
-
|
|
345
|
-
```js
|
|
346
|
-
function createStores(...keys):StoreCollection
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
#### parameters
|
|
350
|
-
|
|
351
|
-
* keys - multiple model keys of model functions.
|
|
352
|
-
|
|
353
|
-
#### return
|
|
354
|
-
|
|
355
|
-
StoreCollection created by the model keys.
|
|
356
|
-
|
|
357
|
-
**StoreCollection** structure:
|
|
358
|
-
|
|
359
|
-
```js
|
|
360
|
-
{
|
|
361
|
-
find: (key)=>store,
|
|
362
|
-
destroy: ()=>void
|
|
363
|
-
}
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
### createSignal
|
|
367
|
-
|
|
368
|
-
```js
|
|
369
|
-
function createSignal(store):SignalStore
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
#### parameters
|
|
373
|
-
|
|
374
|
-
* store - a store object created by `createStore` method.
|
|
375
|
-
|
|
376
|
-
#### return
|
|
377
|
-
|
|
378
|
-
Signal store object with `subscribe` method to subscribe the state changes, and `getSignal` method to get the Signal callback function.
|
|
379
|
-
|
|
380
|
-
**SignalStore** structure:
|
|
381
|
-
|
|
382
|
-
```js
|
|
383
|
-
{
|
|
384
|
-
subscribe: (listener)=>unsubscribe,
|
|
385
|
-
getSignal: ()=>Signal,
|
|
386
|
-
key: modelKey,
|
|
387
|
-
}
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
The Signal function returns a real time instance from store. Only when the properties picked from real time instance are changed, the subscribed listener can receive an action notification.
|
|
391
|
-
|
|
392
|
-
```js
|
|
393
|
-
// Signal
|
|
394
|
-
function signal():instance;
|
|
395
|
-
// to start statistic the picked properties change
|
|
396
|
-
signal.startStatistics():void;
|
|
397
|
-
// to end statistic the picked properties change
|
|
398
|
-
signal.stopStatistics():void;
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
### createSelector
|
|
402
|
-
|
|
403
|
-
```js
|
|
404
|
-
function createSelector(store, opts?:SelectorOptions):SelectorStore
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
#### parameters
|
|
408
|
-
|
|
409
|
-
* store - a store object created by `createStore` method.
|
|
410
|
-
* opts - (Optional) an object config to optimize createSelector.
|
|
411
|
-
|
|
412
|
-
```js
|
|
413
|
-
// opts
|
|
414
|
-
{
|
|
415
|
-
// When the selector is drived to reproduce a new data,
|
|
416
|
-
// it compares if the result is different with the previous one,
|
|
417
|
-
// if the camparing result is true, it represents no differ happens,
|
|
418
|
-
// the subscribed callback will not be called.
|
|
419
|
-
equality?: (current: T, next: T) => boolean;
|
|
420
|
-
}
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
#### return
|
|
424
|
-
|
|
425
|
-
Selector store object with `subscribe` method to subscribe the state changes, and `select` method for reselecting instance.
|
|
426
|
-
|
|
427
|
-
```js
|
|
428
|
-
{
|
|
429
|
-
subscribe: (listener)=>unsubscribe,
|
|
430
|
-
select: (selector?:(getInstance:()=>Instance)=>)=>any,
|
|
431
|
-
key: modelKey,
|
|
432
|
-
}
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
### model
|
|
437
|
-
|
|
438
|
-
```js
|
|
439
|
-
function model(modelFn):ModelUsage
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
#### parameters
|
|
443
|
-
|
|
444
|
-
* modelFn - a model function accepts a state parameter and returns an object with action methods.
|
|
445
|
-
|
|
446
|
-
#### return
|
|
447
|
-
|
|
448
|
-
ModelUsage object with `createStore`, `createKey` methods to create store, key for the model function, and `select` method to set a default selector function (Use `createSelector(store).select()` to select the default one).
|
|
449
|
-
|
|
450
|
-
**ModelUsage** structure:
|
|
451
|
-
|
|
452
|
-
```js
|
|
453
|
-
{
|
|
454
|
-
createStore: (initialState?)=> store,
|
|
455
|
-
createKey: (initialState?)=> key,
|
|
456
|
-
select: (
|
|
457
|
-
selector:(getInstance:()=>Instance)=>Record<string, any>|Array<any>
|
|
458
|
-
)=>ModelUsage
|
|
459
|
-
}
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
### config
|
|
463
|
-
|
|
464
|
-
```js
|
|
465
|
-
function config(options):configAPI
|
|
466
|
-
```
|
|
467
|
-
|
|
468
|
-
#### parameters
|
|
469
|
-
|
|
470
|
-
##### options - (Optional) an object with the following properties:
|
|
471
|
-
* notify - (Optional) a callback function for noticing an action to every subscriber, it accepts a notifier function and an action as parameters.
|
|
472
|
-
* controlled - (Optional) a boolean state to tell as-model use controlled mode to output instance changes.
|
|
473
|
-
* middleWares - (Optional) a middleWare array for reproducing state or ignore actions.
|
|
474
|
-
|
|
475
|
-
#### return
|
|
476
|
-
|
|
477
|
-
All apis above except `createSignal` and `createSelector` API.
|
|
478
|
-
|
|
479
|
-
```js
|
|
480
|
-
{
|
|
481
|
-
createStore: (modelFnOrKey, initialState?)=>store,
|
|
482
|
-
createKey: (modelFn, initialState?)=>key,
|
|
483
|
-
createStores: (...keys)=>stores,
|
|
484
|
-
model: (modelFn)=>ModelUsage
|
|
485
|
-
}
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
### validations
|
|
489
|
-
|
|
490
|
-
A validate callback collection object.
|
|
491
|
-
|
|
492
|
-
#### validations.isInstanceFromNoStateModel
|
|
493
|
-
|
|
494
|
-
```js
|
|
495
|
-
function isInstanceFromNoStateModel(instance: any): boolean
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
To validate if the parameter object is a uninitialized store instance.
|
|
499
|
-
|
|
500
|
-
#### validations.isModelKey
|
|
501
|
-
|
|
502
|
-
```js
|
|
503
|
-
function isModelKey<
|
|
504
|
-
S,
|
|
505
|
-
T extends ModelInstance,
|
|
506
|
-
R extends (ins: () => T) => any = (ins: () => T) => T
|
|
507
|
-
>(
|
|
508
|
-
data: any
|
|
509
|
-
): data is ModelKey<S, T, R>;
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
To validate if the parameter object is a model key.
|
|
513
|
-
|
|
514
|
-
#### validations.isModelStore
|
|
515
|
-
|
|
516
|
-
```js
|
|
517
|
-
function isModelStore<
|
|
518
|
-
S,
|
|
519
|
-
T extends ModelInstance,
|
|
520
|
-
R extends (ins: () => T) => any = (ins: () => T) => T
|
|
521
|
-
>(
|
|
522
|
-
data: any
|
|
523
|
-
): data is Store<S, T, R>;
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
To validate if the parameter object is a store.
|
|
527
|
-
|
|
528
|
-
#### validations.isModelUsage
|
|
529
|
-
|
|
530
|
-
```js
|
|
531
|
-
function isModelUsage<
|
|
532
|
-
S,
|
|
533
|
-
T extends ModelInstance,
|
|
534
|
-
R extends (ins: () => T) => any = (ins: () => T) => T
|
|
535
|
-
>(
|
|
536
|
-
data: any
|
|
537
|
-
): data is ModelUsage<S, T, R>;
|
|
538
|
-
```
|
|
539
|
-
|
|
540
|
-
To validate if the parameter object is a model usage. A model usage is created by API **model**, it is a tool collection provides **createKey**, **createStore**, **select** APIs based on the model.
|
|
541
|
-
|
|
542
|
-
### shallowEqual
|
|
543
|
-
|
|
544
|
-
```js
|
|
545
|
-
function shallowEqual(prev: any, current: any): boolean
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
To validate if the value of left is shallow equal with the value of right.
|
|
549
|
-
|
|
550
|
-
## Browser Support
|
|
551
|
-
|
|
552
|
-
```
|
|
553
|
-
chrome: '>=91',
|
|
554
|
-
edge: '>=91',
|
|
555
|
-
firefox: '=>90',
|
|
556
|
-
safari: '>=15'
|
|
557
|
-
```
|
|
558
|
-
|
|
1
|
+
[![npm][npm-image]][npm-url]
|
|
2
|
+
[![NPM downloads][npm-downloads-image]][npm-url]
|
|
3
|
+
[![standard][standard-image]][standard-url]
|
|
4
|
+
|
|
5
|
+
[npm-image]: https://img.shields.io/npm/v/as-model.svg?style=flat-square
|
|
6
|
+
[npm-url]: https://www.npmjs.com/package/as-model
|
|
7
|
+
[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square
|
|
8
|
+
[standard-url]: http://npm.im/standard
|
|
9
|
+
[npm-downloads-image]: https://img.shields.io/npm/dm/as-model.svg?style=flat-square
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# as-model
|
|
13
|
+
|
|
14
|
+
This is a simple state management library with model coding style for javascript/typescript.
|
|
15
|
+
|
|
16
|
+
## Code first
|
|
17
|
+
|
|
18
|
+
Create a model function:
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
// model.js
|
|
22
|
+
// A parameter for model state.
|
|
23
|
+
export function counting(state){
|
|
24
|
+
// Define instance object for outside usage.
|
|
25
|
+
return {
|
|
26
|
+
// Define properties for instance.
|
|
27
|
+
count: state,
|
|
28
|
+
symbol: !state? '': (state > 0? '+' : '-'),
|
|
29
|
+
// Create action methods for changing state.
|
|
30
|
+
increase:()=> state + 1,
|
|
31
|
+
decrease:()=> state - 1,
|
|
32
|
+
add(...additions){
|
|
33
|
+
return additions.reduce((result, current)=>{
|
|
34
|
+
return result + current;
|
|
35
|
+
}, state);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Create store:
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
// store.js
|
|
45
|
+
import {counting} from './model';
|
|
46
|
+
import {createStore} from 'as-model';
|
|
47
|
+
|
|
48
|
+
// Create and initialize a model store.
|
|
49
|
+
const store = createStore(counting, 0);
|
|
50
|
+
// Get instance and call action methods to change state.
|
|
51
|
+
store.getInstance().increase();
|
|
52
|
+
// Get new properties from instance.
|
|
53
|
+
console.log(store.getInstance().count); // 1
|
|
54
|
+
store.getInstance().add(2,3);
|
|
55
|
+
console.log(store.getInstance().count); // 6
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Create multiple stores:
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
import {counting} from './model';
|
|
62
|
+
import {createKey, createStores} from 'as-model';
|
|
63
|
+
|
|
64
|
+
// Create model key with initial state.
|
|
65
|
+
const countingKey0 = createKey(counting, 0);
|
|
66
|
+
const countingKey1 = createKey(counting, 1);
|
|
67
|
+
|
|
68
|
+
// Use model keys as templates to create multiple stores.
|
|
69
|
+
const stores = createStores(countingKey0, countingKey1);
|
|
70
|
+
// Find store by model key
|
|
71
|
+
const store0 = stores.find(countingKey0);
|
|
72
|
+
store0?.getInstance().increase();
|
|
73
|
+
console.log(store0?.getInstance().count); // 1
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Model key is a template for creating multiple stores, and it is also an identifier to find the right store from multiple stores.
|
|
77
|
+
|
|
78
|
+
Use **model** API to create store or key.
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
import {counting} from './model';
|
|
82
|
+
import {model} from 'as-model';
|
|
83
|
+
|
|
84
|
+
const store = model(counting).createStore(0);
|
|
85
|
+
const key = model(counting).createKey(0);
|
|
86
|
+
......
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
In typescript develop environment, `model` API can do a type check for making sure every model action method returns a correct type.
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
// ts
|
|
93
|
+
import {model} from 'as-model';
|
|
94
|
+
|
|
95
|
+
// The model api ensures every action method returns a same type value with model state.
|
|
96
|
+
const counting = model((state: number)=>{
|
|
97
|
+
return {
|
|
98
|
+
count: state,
|
|
99
|
+
increase:()=>state + 1 + '', // type error, should be number, but returns string.
|
|
100
|
+
decrease:()=>state - 1,
|
|
101
|
+
add(...additions: number[]){
|
|
102
|
+
return additions.reduce((result, current)=>{
|
|
103
|
+
return result + current;
|
|
104
|
+
}, state);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const store = counting.createStore(0);
|
|
110
|
+
const key = counting.createKey(0);
|
|
111
|
+
......
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Subscribe store
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
import {counting} from './model';
|
|
118
|
+
import {model} from 'as-model';
|
|
119
|
+
|
|
120
|
+
const store = model(counting).createStore(0);
|
|
121
|
+
const {getInstance} = store;
|
|
122
|
+
// Subscribe the state changes.
|
|
123
|
+
const unsubscribe = store.subscribe((action)=>{
|
|
124
|
+
console.log(store.getInstance());
|
|
125
|
+
});
|
|
126
|
+
getInstance().increase(); // output: {count: 1}
|
|
127
|
+
// Destroy subscription.
|
|
128
|
+
unsubscribe();
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Want to use async operations?
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
import {counting} from './model';
|
|
135
|
+
import {model, createSelector} from 'as-model';
|
|
136
|
+
|
|
137
|
+
const store = model(counting).select((getInstance)=>{
|
|
138
|
+
const instance = getInstance();
|
|
139
|
+
return {
|
|
140
|
+
...instance,
|
|
141
|
+
async delayIncrease(){
|
|
142
|
+
const ok = await new Promise((resolve)=>{
|
|
143
|
+
setTimeout(()=>{
|
|
144
|
+
resolve(true);
|
|
145
|
+
},200);
|
|
146
|
+
});
|
|
147
|
+
if(ok){
|
|
148
|
+
getInstance().increase();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}).createStore(0);
|
|
153
|
+
|
|
154
|
+
const {subscribe, select} = createSelector(store);
|
|
155
|
+
const unsubscribe = subscribe();
|
|
156
|
+
// When use select with no parameter,
|
|
157
|
+
// select method finds default selector for reproducing result
|
|
158
|
+
const {delayIncrease} = select();
|
|
159
|
+
await delayIncrease();
|
|
160
|
+
select().count // 1
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Subscribe store in react hooks:
|
|
164
|
+
|
|
165
|
+
```js
|
|
166
|
+
import {model, createStores} from 'as-model';
|
|
167
|
+
import {
|
|
168
|
+
createContext,
|
|
169
|
+
useRef,
|
|
170
|
+
useState,
|
|
171
|
+
useEffect,
|
|
172
|
+
useContext
|
|
173
|
+
} from 'react';
|
|
174
|
+
|
|
175
|
+
// Local state management
|
|
176
|
+
function useModel(modelFn, defaultState){
|
|
177
|
+
// Use ref to persist the store object.
|
|
178
|
+
const storeRef = useRef(model(modelFn).createStore(defaultState));
|
|
179
|
+
const store = storeRef.current;
|
|
180
|
+
// Set store instance as an initial state for useState.
|
|
181
|
+
const [state, setState] = useState(store.getInstance());
|
|
182
|
+
|
|
183
|
+
useEffect(()=>{
|
|
184
|
+
// Subscribe the state changes.
|
|
185
|
+
const unsubscribe = store.subscribe((action)=>{
|
|
186
|
+
setState(store.getInstance());
|
|
187
|
+
});
|
|
188
|
+
// Destroy subscription when component unmounts.
|
|
189
|
+
return unsubscribe;
|
|
190
|
+
}, []);
|
|
191
|
+
|
|
192
|
+
return state;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function App(){
|
|
196
|
+
const {
|
|
197
|
+
count,
|
|
198
|
+
increase
|
|
199
|
+
} = useModel(counting, 0);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// global static state management
|
|
203
|
+
function useModelStore(store){
|
|
204
|
+
const [state, setState] = useState(store.getInstance());
|
|
205
|
+
|
|
206
|
+
useEffect(()=>{
|
|
207
|
+
const unsubscribe = store.subscribe((action)=>{
|
|
208
|
+
setState(store.getInstance());
|
|
209
|
+
});
|
|
210
|
+
return unsubscribe;
|
|
211
|
+
}, []);
|
|
212
|
+
|
|
213
|
+
return state;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const store = model(counting).createStore({state: 0});
|
|
217
|
+
|
|
218
|
+
function App(){
|
|
219
|
+
const {
|
|
220
|
+
count,
|
|
221
|
+
increase
|
|
222
|
+
} = useModelStore(store);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// global dynamic state management
|
|
226
|
+
const ModelContext = createContext(null);
|
|
227
|
+
|
|
228
|
+
function create(...keys){
|
|
229
|
+
return {
|
|
230
|
+
provide(Component){
|
|
231
|
+
return function Provider(props){
|
|
232
|
+
// Create and persist multiple stores in Component, that makes different elements from this Component carry different stores.
|
|
233
|
+
const storesRef = useRef(createStores(...keys));
|
|
234
|
+
const stores = storesRef.current;
|
|
235
|
+
// Use Context to provide multiple stores to all the children.
|
|
236
|
+
return (
|
|
237
|
+
<ModelContext.Provider value={stores}>
|
|
238
|
+
<Component {...props} />
|
|
239
|
+
</ModelContext.Provider>
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function useModelKey(key){
|
|
247
|
+
const stores = useContext(ModelContext);
|
|
248
|
+
if(stores==null){
|
|
249
|
+
throw new Error('ModelContext is not provided');
|
|
250
|
+
}
|
|
251
|
+
// Use model key to find the right store.
|
|
252
|
+
const store = stores.find(key);
|
|
253
|
+
if(store==null){
|
|
254
|
+
throw new Error('Can not find store by model key');
|
|
255
|
+
}
|
|
256
|
+
const [state, setState] = useState(store.getInstance());
|
|
257
|
+
|
|
258
|
+
useEffect(()=>{
|
|
259
|
+
const unsubscribe = store.subscribe((action)=>{
|
|
260
|
+
setState(store.getInstance());
|
|
261
|
+
});
|
|
262
|
+
return unsubscribe;
|
|
263
|
+
}, []);
|
|
264
|
+
|
|
265
|
+
return state;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const countingKey = model(counting).createKey(0);
|
|
269
|
+
|
|
270
|
+
const App = create(countingKey).provide(function App(){
|
|
271
|
+
const {
|
|
272
|
+
count,
|
|
273
|
+
increase
|
|
274
|
+
} = useModelKey(countingKey);
|
|
275
|
+
});
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Install
|
|
279
|
+
|
|
280
|
+
```
|
|
281
|
+
npm install as-model
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Simplify API
|
|
285
|
+
|
|
286
|
+
### createStore
|
|
287
|
+
|
|
288
|
+
```js
|
|
289
|
+
function createStore(modelFnOrKey, initialState?):store
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
#### parameters
|
|
293
|
+
|
|
294
|
+
* modelFnOrKey - a model function accepts a state parameter and returns an object with action methods, or a model key of model function.
|
|
295
|
+
* initialState - the initial state of the model.
|
|
296
|
+
|
|
297
|
+
#### return
|
|
298
|
+
|
|
299
|
+
A store object with model key and methods. The store object has `getInstance` method to get the instance of the model; `subscribe` method to subscribe the state changes; `update` method to update the store with new model function and initial state; `destroy` method to destroy the store.
|
|
300
|
+
|
|
301
|
+
**store** structure:
|
|
302
|
+
|
|
303
|
+
```js
|
|
304
|
+
{
|
|
305
|
+
getInstance: ()=>instance,
|
|
306
|
+
subscribe: (listener)=>unsubscribe,
|
|
307
|
+
key: modelKey,
|
|
308
|
+
destroy: ()=>void,
|
|
309
|
+
update: (
|
|
310
|
+
data:{
|
|
311
|
+
model?:modelFn,
|
|
312
|
+
key?: modelKey,
|
|
313
|
+
initialState?: any
|
|
314
|
+
state?: any;
|
|
315
|
+
}
|
|
316
|
+
)=>void,
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### createKey
|
|
321
|
+
|
|
322
|
+
```js
|
|
323
|
+
function createKey(modelFn, initialState?):key
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
#### parameters
|
|
327
|
+
|
|
328
|
+
* modelFn - a model function accepts a state parameter and returns an object with action methods.
|
|
329
|
+
* initialState - the initial state of the model.
|
|
330
|
+
|
|
331
|
+
#### return
|
|
332
|
+
|
|
333
|
+
A model key function with `createStore` method to create a store with the model key.
|
|
334
|
+
|
|
335
|
+
**key** structure:
|
|
336
|
+
|
|
337
|
+
```js
|
|
338
|
+
{
|
|
339
|
+
createStore: (initialState?)=>Store
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### createStores
|
|
344
|
+
|
|
345
|
+
```js
|
|
346
|
+
function createStores(...keys):StoreCollection
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### parameters
|
|
350
|
+
|
|
351
|
+
* keys - multiple model keys of model functions.
|
|
352
|
+
|
|
353
|
+
#### return
|
|
354
|
+
|
|
355
|
+
StoreCollection created by the model keys.
|
|
356
|
+
|
|
357
|
+
**StoreCollection** structure:
|
|
358
|
+
|
|
359
|
+
```js
|
|
360
|
+
{
|
|
361
|
+
find: (key)=>store,
|
|
362
|
+
destroy: ()=>void
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### createSignal
|
|
367
|
+
|
|
368
|
+
```js
|
|
369
|
+
function createSignal(store):SignalStore
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
#### parameters
|
|
373
|
+
|
|
374
|
+
* store - a store object created by `createStore` method.
|
|
375
|
+
|
|
376
|
+
#### return
|
|
377
|
+
|
|
378
|
+
Signal store object with `subscribe` method to subscribe the state changes, and `getSignal` method to get the Signal callback function.
|
|
379
|
+
|
|
380
|
+
**SignalStore** structure:
|
|
381
|
+
|
|
382
|
+
```js
|
|
383
|
+
{
|
|
384
|
+
subscribe: (listener)=>unsubscribe,
|
|
385
|
+
getSignal: ()=>Signal,
|
|
386
|
+
key: modelKey,
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
The Signal function returns a real time instance from store. Only when the properties picked from real time instance are changed, the subscribed listener can receive an action notification.
|
|
391
|
+
|
|
392
|
+
```js
|
|
393
|
+
// Signal
|
|
394
|
+
function signal():instance;
|
|
395
|
+
// to start statistic the picked properties change
|
|
396
|
+
signal.startStatistics():void;
|
|
397
|
+
// to end statistic the picked properties change
|
|
398
|
+
signal.stopStatistics():void;
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### createSelector
|
|
402
|
+
|
|
403
|
+
```js
|
|
404
|
+
function createSelector(store, opts?:SelectorOptions):SelectorStore
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
#### parameters
|
|
408
|
+
|
|
409
|
+
* store - a store object created by `createStore` method.
|
|
410
|
+
* opts - (Optional) an object config to optimize createSelector.
|
|
411
|
+
|
|
412
|
+
```js
|
|
413
|
+
// opts
|
|
414
|
+
{
|
|
415
|
+
// When the selector is drived to reproduce a new data,
|
|
416
|
+
// it compares if the result is different with the previous one,
|
|
417
|
+
// if the camparing result is true, it represents no differ happens,
|
|
418
|
+
// the subscribed callback will not be called.
|
|
419
|
+
equality?: (current: T, next: T) => boolean;
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
#### return
|
|
424
|
+
|
|
425
|
+
Selector store object with `subscribe` method to subscribe the state changes, and `select` method for reselecting instance.
|
|
426
|
+
|
|
427
|
+
```js
|
|
428
|
+
{
|
|
429
|
+
subscribe: (listener)=>unsubscribe,
|
|
430
|
+
select: (selector?:(getInstance:()=>Instance)=>)=>any,
|
|
431
|
+
key: modelKey,
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
### model
|
|
437
|
+
|
|
438
|
+
```js
|
|
439
|
+
function model(modelFn):ModelUsage
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
#### parameters
|
|
443
|
+
|
|
444
|
+
* modelFn - a model function accepts a state parameter and returns an object with action methods.
|
|
445
|
+
|
|
446
|
+
#### return
|
|
447
|
+
|
|
448
|
+
ModelUsage object with `createStore`, `createKey` methods to create store, key for the model function, and `select` method to set a default selector function (Use `createSelector(store).select()` to select the default one).
|
|
449
|
+
|
|
450
|
+
**ModelUsage** structure:
|
|
451
|
+
|
|
452
|
+
```js
|
|
453
|
+
{
|
|
454
|
+
createStore: (initialState?)=> store,
|
|
455
|
+
createKey: (initialState?)=> key,
|
|
456
|
+
select: (
|
|
457
|
+
selector:(getInstance:()=>Instance)=>Record<string, any>|Array<any>
|
|
458
|
+
)=>ModelUsage
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### config
|
|
463
|
+
|
|
464
|
+
```js
|
|
465
|
+
function config(options):configAPI
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
#### parameters
|
|
469
|
+
|
|
470
|
+
##### options - (Optional) an object with the following properties:
|
|
471
|
+
* notify - (Optional) a callback function for noticing an action to every subscriber, it accepts a notifier function and an action as parameters.
|
|
472
|
+
* controlled - (Optional) a boolean state to tell as-model use controlled mode to output instance changes.
|
|
473
|
+
* middleWares - (Optional) a middleWare array for reproducing state or ignore actions.
|
|
474
|
+
|
|
475
|
+
#### return
|
|
476
|
+
|
|
477
|
+
All apis above except `createSignal` and `createSelector` API.
|
|
478
|
+
|
|
479
|
+
```js
|
|
480
|
+
{
|
|
481
|
+
createStore: (modelFnOrKey, initialState?)=>store,
|
|
482
|
+
createKey: (modelFn, initialState?)=>key,
|
|
483
|
+
createStores: (...keys)=>stores,
|
|
484
|
+
model: (modelFn)=>ModelUsage
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### validations
|
|
489
|
+
|
|
490
|
+
A validate callback collection object.
|
|
491
|
+
|
|
492
|
+
#### validations.isInstanceFromNoStateModel
|
|
493
|
+
|
|
494
|
+
```js
|
|
495
|
+
function isInstanceFromNoStateModel(instance: any): boolean
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
To validate if the parameter object is a uninitialized store instance.
|
|
499
|
+
|
|
500
|
+
#### validations.isModelKey
|
|
501
|
+
|
|
502
|
+
```js
|
|
503
|
+
function isModelKey<
|
|
504
|
+
S,
|
|
505
|
+
T extends ModelInstance,
|
|
506
|
+
R extends (ins: () => T) => any = (ins: () => T) => T
|
|
507
|
+
>(
|
|
508
|
+
data: any
|
|
509
|
+
): data is ModelKey<S, T, R>;
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
To validate if the parameter object is a model key.
|
|
513
|
+
|
|
514
|
+
#### validations.isModelStore
|
|
515
|
+
|
|
516
|
+
```js
|
|
517
|
+
function isModelStore<
|
|
518
|
+
S,
|
|
519
|
+
T extends ModelInstance,
|
|
520
|
+
R extends (ins: () => T) => any = (ins: () => T) => T
|
|
521
|
+
>(
|
|
522
|
+
data: any
|
|
523
|
+
): data is Store<S, T, R>;
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
To validate if the parameter object is a store.
|
|
527
|
+
|
|
528
|
+
#### validations.isModelUsage
|
|
529
|
+
|
|
530
|
+
```js
|
|
531
|
+
function isModelUsage<
|
|
532
|
+
S,
|
|
533
|
+
T extends ModelInstance,
|
|
534
|
+
R extends (ins: () => T) => any = (ins: () => T) => T
|
|
535
|
+
>(
|
|
536
|
+
data: any
|
|
537
|
+
): data is ModelUsage<S, T, R>;
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
To validate if the parameter object is a model usage. A model usage is created by API **model**, it is a tool collection provides **createKey**, **createStore**, **select** APIs based on the model.
|
|
541
|
+
|
|
542
|
+
### shallowEqual
|
|
543
|
+
|
|
544
|
+
```js
|
|
545
|
+
function shallowEqual(prev: any, current: any): boolean
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
To validate if the value of left is shallow equal with the value of right.
|
|
549
|
+
|
|
550
|
+
## Browser Support
|
|
551
|
+
|
|
552
|
+
```
|
|
553
|
+
chrome: '>=91',
|
|
554
|
+
edge: '>=91',
|
|
555
|
+
firefox: '=>90',
|
|
556
|
+
safari: '>=15'
|
|
557
|
+
```
|
|
558
|
+
|
package/index.d.ts
CHANGED
|
@@ -27,9 +27,7 @@ declare type ValidInstance<S, T extends ModelInstance> = {
|
|
|
27
27
|
: T[K];
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
export declare type Model
|
|
31
|
-
state: S
|
|
32
|
-
) => ValidInstance<S, T>;
|
|
30
|
+
export declare type Model = (state: any) => any;
|
|
33
31
|
|
|
34
32
|
export type PickState<R extends Model> = R extends (state: infer S) => any
|
|
35
33
|
? S
|
|
@@ -57,7 +55,7 @@ export interface Token {
|
|
|
57
55
|
export declare type Dispatch = (action: Action) => any;
|
|
58
56
|
|
|
59
57
|
export declare interface Key<
|
|
60
|
-
M extends Model =
|
|
58
|
+
M extends Model = Model,
|
|
61
59
|
R extends undefined | ((instance: () => Instance<M>) => any) = undefined
|
|
62
60
|
> extends M {
|
|
63
61
|
(s: PickState<M>): Instance<M>;
|
|
@@ -68,7 +66,7 @@ export declare interface Key<
|
|
|
68
66
|
defaultState?: PickState<M>;
|
|
69
67
|
}
|
|
70
68
|
|
|
71
|
-
declare interface UpdaterStore<S = any, T
|
|
69
|
+
declare interface UpdaterStore<S = any, T = any> {
|
|
72
70
|
getState: () => { state: S; instance: T };
|
|
73
71
|
dispatch: (action: Action) => void;
|
|
74
72
|
}
|
|
@@ -89,14 +87,14 @@ export declare interface Config {
|
|
|
89
87
|
/** createStore * */
|
|
90
88
|
|
|
91
89
|
export declare interface StoreIndex<
|
|
92
|
-
M extends Model =
|
|
90
|
+
M extends Model = Model,
|
|
93
91
|
R extends undefined | ((instance: () => Instance<M>) => any) = any
|
|
94
92
|
> {
|
|
95
93
|
key: Key<M, R>;
|
|
96
94
|
}
|
|
97
95
|
|
|
98
96
|
export declare interface Store<
|
|
99
|
-
M extends Model =
|
|
97
|
+
M extends Model = Model,
|
|
100
98
|
R extends undefined | ((instance: () => Instance<M>) => any) = undefined
|
|
101
99
|
> extends StoreIndex<M, R> {
|
|
102
100
|
subscribe: (dispatcher: Dispatch) => () => void;
|
|
@@ -128,16 +126,15 @@ export declare function createStore<
|
|
|
128
126
|
/** createKey * */
|
|
129
127
|
|
|
130
128
|
export declare interface ModelKey<
|
|
131
|
-
M extends Model =
|
|
129
|
+
M extends Model = Model,
|
|
132
130
|
R extends undefined | ((instance: () => Instance<M>) => any) = undefined
|
|
133
131
|
> extends Key<M, R> {
|
|
134
|
-
(s: PickState<M>): Instance<M>;
|
|
135
132
|
createStore: <D extends PickState<M>>(initialState?: D) => Store<M, R>;
|
|
136
133
|
extends: <E extends Record<string, any>>(e: E) => ModelKey<M, R> & E;
|
|
137
134
|
}
|
|
138
135
|
|
|
139
136
|
export declare function createKey<
|
|
140
|
-
M extends Model =
|
|
137
|
+
M extends Model = Model,
|
|
141
138
|
D extends PickState<M>,
|
|
142
139
|
R extends undefined | ((instance: () => Instance<M>) => any) = undefined
|
|
143
140
|
>(model: M | ModelUsage<M, R>, initialState?: D): ModelKey<M, R>;
|
|
@@ -146,7 +143,7 @@ export declare function createKey<
|
|
|
146
143
|
|
|
147
144
|
export declare interface StoreCollection {
|
|
148
145
|
find: <
|
|
149
|
-
M extends Model =
|
|
146
|
+
M extends Model = Model,
|
|
150
147
|
R extends undefined | ((instance: () => Instance<M>) => any) = undefined
|
|
151
148
|
>(
|
|
152
149
|
key: Key<M, R> | StoreIndex<M, R>
|
|
@@ -210,7 +207,7 @@ export interface SignalOptions {
|
|
|
210
207
|
|
|
211
208
|
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
212
209
|
declare interface SignalStore<
|
|
213
|
-
M extends Model =
|
|
210
|
+
M extends Model = Model,
|
|
214
211
|
R extends undefined | ((instance: () => Instance<M>) => any) = undefined
|
|
215
212
|
> extends StoreIndex<M, R> {
|
|
216
213
|
getToken: () => Token;
|
|
@@ -229,7 +226,7 @@ declare interface SignalStore<
|
|
|
229
226
|
}
|
|
230
227
|
|
|
231
228
|
export declare function createSignal<
|
|
232
|
-
M extends Model =
|
|
229
|
+
M extends Model = Model,
|
|
233
230
|
R extends undefined | ((instance: () => Instance<M>) => any) = undefined
|
|
234
231
|
>(store: Store<M, R>): SignalStore<M, R>;
|
|
235
232
|
|
|
@@ -264,7 +261,7 @@ declare type SelectMethod<
|
|
|
264
261
|
|
|
265
262
|
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
|
266
263
|
declare interface SelectorStore<
|
|
267
|
-
M extends Model =
|
|
264
|
+
M extends Model = Model,
|
|
268
265
|
R extends undefined | ((instance: () => Instance<M>) => any) = undefined
|
|
269
266
|
> extends StoreIndex<M, R> {
|
|
270
267
|
getToken: () => Token;
|
|
@@ -277,7 +274,7 @@ declare interface SelectorOption<T = any> {
|
|
|
277
274
|
}
|
|
278
275
|
|
|
279
276
|
export declare function createSelector<
|
|
280
|
-
M extends Model =
|
|
277
|
+
M extends Model = Model,
|
|
281
278
|
R extends undefined | ((instance: () => Instance<M>) => any) = undefined
|
|
282
279
|
>(store: Store<M, R>, opts?: SelectorOption): SelectorStore<M, R>;
|
|
283
280
|
|
package/package.json
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
{
|
|
2
|
-
"private": false,
|
|
3
|
-
"name": "as-model",
|
|
4
|
-
"version": "0.3.
|
|
5
|
-
"description": "This is a model state management tool",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"author": "Jimmy.Harding",
|
|
8
|
-
"homepage": "https://github.com/filefoxper/a-model",
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "https://github.com/filefoxper/a-model"
|
|
12
|
-
},
|
|
13
|
-
"main": "dist/index.js",
|
|
14
|
-
"module": "esm/index.js",
|
|
15
|
-
"files": [
|
|
16
|
-
"dist",
|
|
17
|
-
"esm",
|
|
18
|
-
"index.d.ts"
|
|
19
|
-
],
|
|
20
|
-
"scripts": {
|
|
21
|
-
"build": "node ./build.js",
|
|
22
|
-
"docs": "docsify serve ./docs",
|
|
23
|
-
"lint": "eslint src --fix --ext .ts,.tsx ",
|
|
24
|
-
"lint-init": "eslint --init",
|
|
25
|
-
"test": "jest --coverage"
|
|
26
|
-
},
|
|
27
|
-
"typings": "index.d.ts",
|
|
28
|
-
"devDependencies": {
|
|
29
|
-
"@babel/cli": "^7.27.2",
|
|
30
|
-
"@babel/core": "^7.27.4",
|
|
31
|
-
"@babel/eslint-parser": "^7.27.5",
|
|
32
|
-
"@babel/plugin-transform-runtime": "^7.27.4",
|
|
33
|
-
"@babel/preset-env": "^7.27.2",
|
|
34
|
-
"@babel/preset-typescript": "^7.27.1",
|
|
35
|
-
"@babel/runtime": "^7.27.6",
|
|
36
|
-
"@pmnps/plugin-publish": "4.5.0",
|
|
37
|
-
"@types/jest": "^29.5.14",
|
|
38
|
-
"babel-jest": "29.7.0",
|
|
39
|
-
"esbuild": "^0.25.0",
|
|
40
|
-
"esbuild-plugin-es5": "2.1.1",
|
|
41
|
-
"eslint": "^8.49.0",
|
|
42
|
-
"eslint-config-airbnb": "^19.0.4",
|
|
43
|
-
"eslint-config-airbnb-typescript": "^17.1.0",
|
|
44
|
-
"eslint-config-prettier": "^9.0.0",
|
|
45
|
-
"eslint-import-resolver-typescript": "^3.6.0",
|
|
46
|
-
"eslint-plugin-import": "^2.28.1",
|
|
47
|
-
"eslint-plugin-jsx-a11y": "^6.7.1",
|
|
48
|
-
"eslint-plugin-prettier": "^5.0.0",
|
|
49
|
-
"eslint-plugin-react": "^7.33.2",
|
|
50
|
-
"eslint-plugin-react-hooks": "^4.6.0",
|
|
51
|
-
"eslint-plugin-unused-imports": "^2.0.0",
|
|
52
|
-
"eslint-webpack-plugin": "^4.0.1",
|
|
53
|
-
"jest": "29.7.0",
|
|
54
|
-
"jest-environment-jsdom": "29.7.0",
|
|
55
|
-
"pmnps": "^4.5.3",
|
|
56
|
-
"prettier": "^3.0.3",
|
|
57
|
-
"prettier-eslint": "^15.0.1",
|
|
58
|
-
"prettier-eslint-cli": "^7.1.0",
|
|
59
|
-
"ts-node": "^10.8.1",
|
|
60
|
-
"typescript": "^4.9.5"
|
|
61
|
-
},
|
|
62
|
-
"keywords": [
|
|
63
|
-
"model",
|
|
64
|
-
"state",
|
|
65
|
-
"state-management",
|
|
66
|
-
"typescript"
|
|
67
|
-
]
|
|
68
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"private": false,
|
|
3
|
+
"name": "as-model",
|
|
4
|
+
"version": "0.3.3",
|
|
5
|
+
"description": "This is a model state management tool",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Jimmy.Harding",
|
|
8
|
+
"homepage": "https://github.com/filefoxper/a-model",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/filefoxper/a-model"
|
|
12
|
+
},
|
|
13
|
+
"main": "dist/index.js",
|
|
14
|
+
"module": "esm/index.js",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"esm",
|
|
18
|
+
"index.d.ts"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "node ./build.js",
|
|
22
|
+
"docs": "docsify serve ./docs",
|
|
23
|
+
"lint": "eslint src --fix --ext .ts,.tsx ",
|
|
24
|
+
"lint-init": "eslint --init",
|
|
25
|
+
"test": "jest --coverage"
|
|
26
|
+
},
|
|
27
|
+
"typings": "index.d.ts",
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@babel/cli": "^7.27.2",
|
|
30
|
+
"@babel/core": "^7.27.4",
|
|
31
|
+
"@babel/eslint-parser": "^7.27.5",
|
|
32
|
+
"@babel/plugin-transform-runtime": "^7.27.4",
|
|
33
|
+
"@babel/preset-env": "^7.27.2",
|
|
34
|
+
"@babel/preset-typescript": "^7.27.1",
|
|
35
|
+
"@babel/runtime": "^7.27.6",
|
|
36
|
+
"@pmnps/plugin-publish": "4.5.0",
|
|
37
|
+
"@types/jest": "^29.5.14",
|
|
38
|
+
"babel-jest": "29.7.0",
|
|
39
|
+
"esbuild": "^0.25.0",
|
|
40
|
+
"esbuild-plugin-es5": "2.1.1",
|
|
41
|
+
"eslint": "^8.49.0",
|
|
42
|
+
"eslint-config-airbnb": "^19.0.4",
|
|
43
|
+
"eslint-config-airbnb-typescript": "^17.1.0",
|
|
44
|
+
"eslint-config-prettier": "^9.0.0",
|
|
45
|
+
"eslint-import-resolver-typescript": "^3.6.0",
|
|
46
|
+
"eslint-plugin-import": "^2.28.1",
|
|
47
|
+
"eslint-plugin-jsx-a11y": "^6.7.1",
|
|
48
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
49
|
+
"eslint-plugin-react": "^7.33.2",
|
|
50
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
51
|
+
"eslint-plugin-unused-imports": "^2.0.0",
|
|
52
|
+
"eslint-webpack-plugin": "^4.0.1",
|
|
53
|
+
"jest": "29.7.0",
|
|
54
|
+
"jest-environment-jsdom": "29.7.0",
|
|
55
|
+
"pmnps": "^4.5.3",
|
|
56
|
+
"prettier": "^3.0.3",
|
|
57
|
+
"prettier-eslint": "^15.0.1",
|
|
58
|
+
"prettier-eslint-cli": "^7.1.0",
|
|
59
|
+
"ts-node": "^10.8.1",
|
|
60
|
+
"typescript": "^4.9.5"
|
|
61
|
+
},
|
|
62
|
+
"keywords": [
|
|
63
|
+
"model",
|
|
64
|
+
"state",
|
|
65
|
+
"state-management",
|
|
66
|
+
"typescript"
|
|
67
|
+
]
|
|
68
|
+
}
|