@@ -26,6 +26,7 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
26
26
27
27
state : State < T , E , R > ;
28
28
lastSuccess : SuccessState < T > | InitialState < T > ;
29
+ events ?: InstanceEvents < T , E , R > ;
29
30
30
31
31
32
originalProducer : Producer < T , E , R > | undefined ;
@@ -80,6 +81,27 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
80
81
this . lastSuccess = this . state ;
81
82
82
83
84
+ this . bindMethods ( ) ;
85
+ let instance = this ;
86
+ this . producer = producerWrapper . bind ( null , {
87
+ setProducerType : ( type : ProducerType ) => instance . producerType = type ,
88
+ setState : instance . setState ,
89
+ getState : instance . getState ,
90
+ instance : instance ,
91
+ setSuspender : ( suspender : Promise < T > ) => instance . suspender = suspender ,
92
+ replaceState : instance . replaceState . bind ( instance ) ,
93
+ getProducer : ( ) => instance . originalProducer ,
94
+ } ) ;
95
+
96
+ this . _source = makeSource ( this ) ;
97
+
98
+ if ( __DEV__ ) {
99
+ devtools . emitCreation ( this ) ;
100
+ }
101
+ }
102
+
103
+ private bindMethods ( ) {
104
+ this . on = this . on . bind ( this ) ;
83
105
this . abort = this . abort . bind ( this ) ;
84
106
this . getState = this . getState . bind ( this ) ;
85
107
this . setState = this . setState . bind ( this ) ;
@@ -97,17 +119,6 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
97
119
this . invalidateCache = this . invalidateCache . bind ( this ) ;
98
120
this . replaceProducer = this . replaceProducer . bind ( this ) ;
99
121
100
- let instance = this ;
101
- this . producer = producerWrapper . bind ( null , {
102
- setProducerType : ( type : ProducerType ) => instance . producerType = type ,
103
- setState : instance . setState ,
104
- getState : instance . getState ,
105
- instance : instance ,
106
- setSuspender : ( suspender : Promise < T > ) => instance . suspender = suspender ,
107
- replaceState : instance . replaceState . bind ( instance ) ,
108
- getProducer : ( ) => instance . originalProducer ,
109
- } ) ;
110
-
111
122
this . _source = makeSource ( this ) ;
112
123
113
124
if ( __DEV__ ) {
@@ -128,12 +139,45 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
128
139
return this . config ;
129
140
}
130
141
142
+
143
+ on (
144
+ eventType : InstanceChangeEvent ,
145
+ eventHandler : InstanceChangeEventHandlerType < T , E , R >
146
+ ) : ( ( ) => void )
147
+ on (
148
+ eventType : InstanceDisposeEvent ,
149
+ eventHandler : InstanceDisposeEventHandlerType < T , E , R >
150
+ ) : ( ( ) => void )
151
+ on (
152
+ eventType : InstanceCacheChangeEvent ,
153
+ eventHandler : InstanceCacheChangeEventHandlerType < T , E , R >
154
+ ) : ( ( ) => void )
155
+ on (
156
+ eventType : InstanceEventType ,
157
+ eventHandler : InstanceEventHandlerType < T , E , R >
158
+ ) : ( ( ) => void ) {
159
+ let that = this ;
160
+ if ( ! this . events ) {
161
+ this . events = { } as InstanceEvents < T , E , R > ;
162
+ }
163
+
164
+ // @ts -ignore
165
+ this . events [ eventType ] = eventHandler ;
166
+
167
+ return function ( ) {
168
+ let prevEvent = that . events ! [ eventType ] ;
169
+ if ( prevEvent && prevEvent === eventHandler ) {
170
+ delete that . events ! [ eventType ] ;
171
+ }
172
+ }
173
+
174
+ }
175
+
131
176
patchConfig ( partialConfig ?: Partial < ProducerConfig < T , E , R > > ) {
132
177
Object . assign ( this . config , partialConfig ) ;
133
178
}
134
179
135
180
136
-
137
181
getPayload ( ) : Record < string , any > {
138
182
if ( ! this . payload ) {
139
183
this . payload = { } ;
@@ -208,6 +252,7 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
208
252
if ( __DEV__ ) devtools . startUpdate ( this ) ;
209
253
this . state = newState ;
210
254
this . version += 1 ;
255
+ invokeInstanceEvents ( this , "change" ) ;
211
256
if ( __DEV__ ) devtools . emitUpdate ( this ) ;
212
257
213
258
if ( this . state . status === Status . success ) {
@@ -378,7 +423,10 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
378
423
} ) ;
379
424
}
380
425
381
- runc ( createProducerEffects : ProducerEffectsCreator < T , E , R > , props ?: RUNCProps < T , E , R > ) {
426
+ runc (
427
+ createProducerEffects : ProducerEffectsCreator < T , E , R > ,
428
+ props ?: RUNCProps < T , E , R >
429
+ ) {
382
430
return this . runWithCallbacks ( createProducerEffects , props , props ?. args ?? [ ] ) ;
383
431
}
384
432
@@ -560,6 +608,7 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
560
608
if ( __DEV__ ) devtools . emitDispose ( this ) ;
561
609
562
610
this . willUpdate = false ;
611
+ invokeInstanceEvents ( this , "dispose" ) ;
563
612
return true ;
564
613
}
565
614
@@ -613,6 +662,62 @@ export class AsyncState<T, E, R> implements StateInterface<T, E, R> {
613
662
614
663
//region AsyncState methods helpers
615
664
665
+ function invokeSingleChangeEvent < T , E , R > (
666
+ state : State < T , E , R > ,
667
+ event : StateChangeEventHandler < T , E , R >
668
+ ) {
669
+ if ( isFunction ( event ) ) {
670
+ ( event as ( ( newState : State < T , E , R > ) => void ) ) ( state ) ;
671
+ } else if ( typeof event === "object" && event . status === state . status ) {
672
+ event . handler ( state ) ;
673
+ }
674
+ }
675
+
676
+ function invokeInstanceEvents < T , E , R > (
677
+ instance : StateInterface < T , E , R > , type : InstanceEventType ) {
678
+ if ( ! instance . events || ! instance . events [ type ] ) {
679
+ return ;
680
+ }
681
+ switch ( type ) {
682
+ case "change" : {
683
+ let changeEvents = instance . events [ type ] ;
684
+ if ( changeEvents ) {
685
+ let newState = instance . getState ( ) ;
686
+ if ( Array . isArray ( changeEvents ) ) {
687
+ changeEvents . forEach ( evt => {
688
+ invokeSingleChangeEvent ( newState , evt ) ;
689
+ } ) ;
690
+ } else {
691
+ invokeSingleChangeEvent ( newState , changeEvents ) ;
692
+ }
693
+ }
694
+ return ;
695
+ }
696
+ case "dispose" : {
697
+ let disposeEvents = instance . events [ type ] ;
698
+ if ( disposeEvents ) {
699
+ if ( Array . isArray ( disposeEvents ) ) {
700
+ disposeEvents . forEach ( evt => evt ( ) ) ;
701
+ } else {
702
+ disposeEvents ( ) ;
703
+ }
704
+ }
705
+ return ;
706
+ }
707
+ case "cache-change" : {
708
+ let cacheChangeEvents = instance . events [ type ] ;
709
+ if ( cacheChangeEvents ) {
710
+ if ( Array . isArray ( cacheChangeEvents ) ) {
711
+ cacheChangeEvents . forEach ( evt => evt ( instance . cache ) ) ;
712
+ } else {
713
+ cacheChangeEvents ( instance . cache ) ;
714
+ }
715
+ }
716
+ return ;
717
+ }
718
+ }
719
+ }
720
+
616
721
export type ProducerWrapperInput < T , E , R > = {
617
722
setProducerType ( type : ProducerType ) : void ,
618
723
setState : StateUpdater < T , E , R > ,
@@ -622,6 +727,7 @@ export type ProducerWrapperInput<T, E, R> = {
622
727
replaceState ( newState : State < T , E , R > , notify ?: boolean ) ,
623
728
getProducer ( ) : Producer < T , E , R > | undefined | null ,
624
729
}
730
+
625
731
export function producerWrapper < T , E = any , R = any > (
626
732
input : ProducerWrapperInput < T , E , R > ,
627
733
props : ProducerProps < T , E , R > ,
@@ -996,6 +1102,7 @@ function getTopLevelParent<T, E, R>(base: StateInterface<T, E, R>): StateInterfa
996
1102
}
997
1103
998
1104
function spreadCacheChangeOnLanes < T , E , R > ( topLevelParent : StateInterface < T , E , R > ) {
1105
+ invokeInstanceEvents ( topLevelParent , "cache-change" ) ;
999
1106
if ( ! topLevelParent . lanes ) {
1000
1107
return ;
1001
1108
}
@@ -1013,6 +1120,7 @@ function makeSource<T, E, R>(instance: StateInterface<T, E, R>): Readonly<Source
1013
1120
key : instance . key ,
1014
1121
uniqueId : instance . uniqueId ,
1015
1122
1123
+ on : instance . on ,
1016
1124
abort : instance . abort ,
1017
1125
replay : instance . replay ,
1018
1126
hasLane : instance . hasLane ,
@@ -1313,6 +1421,7 @@ export interface BaseSource<T, E = any, R = any> {
1313
1421
uniqueId : number ,
1314
1422
1315
1423
getVersion ( ) : number ,
1424
+
1316
1425
getPayload ( ) : Record < string , any > ,
1317
1426
1318
1427
mergePayload ( partialPayload ?: Record < string , any > ) ,
@@ -1345,15 +1454,75 @@ export interface BaseSource<T, E = any, R = any> {
1345
1454
patchConfig ( partialConfig ?: Partial < ProducerConfig < T , E , R > > ) ,
1346
1455
1347
1456
getConfig ( ) : ProducerConfig < T , E , R > ,
1457
+
1458
+ on (
1459
+ eventType : InstanceChangeEvent ,
1460
+ eventHandler : InstanceChangeEventHandlerType < T , E , R >
1461
+ ) : ( ( ) => void ) ,
1462
+
1463
+ on (
1464
+ eventType : InstanceDisposeEvent ,
1465
+ eventHandler : InstanceDisposeEventHandlerType < T , E , R >
1466
+ ) : ( ( ) => void ) ,
1467
+
1468
+ on (
1469
+ eventType : InstanceCacheChangeEvent ,
1470
+ eventHandler : InstanceCacheChangeEventHandlerType < T , E , R >
1471
+ ) : ( ( ) => void ) ,
1472
+
1348
1473
}
1349
1474
1475
+
1476
+ export type InstanceEventHandlerType < T , E , R > =
1477
+ InstanceChangeEventHandlerType < T , E , R >
1478
+ |
1479
+ InstanceDisposeEventHandlerType < T , E , R >
1480
+ |
1481
+ InstanceCacheChangeEventHandlerType < T , E , R > ;
1482
+
1483
+
1484
+ export type StateChangeEventHandler < T , E = any , R = any > =
1485
+ ( ( newState : State < T , E , R > ) => void )
1486
+ |
1487
+ InstanceChangeEventObject < T , E , R > ;
1488
+
1489
+ export type InstanceChangeEventObject < T , E = any , R = any > = {
1490
+ status : Status
1491
+ handler : ( ( newState : State < T , E , R > ) => void ) ,
1492
+ }
1493
+
1494
+ export type InstanceChangeEventHandlerType < T , E , R > =
1495
+ StateChangeEventHandler < T , E , R >
1496
+ | StateChangeEventHandler < T , E , R > [ ] ;
1497
+
1498
+ export type InstanceDisposeEventHandlerType < T , E , R > =
1499
+ ( ( ) => void )
1500
+ | ( ( ) => void ) [ ] ;
1501
+ export type InstanceCacheChangeEventHandlerType < T , E , R > =
1502
+ ( ( cache : Record < string , CachedState < T , E , R > > | null | undefined ) => void )
1503
+ | ( ( cache : Record < string , CachedState < T , E , R > > | null | undefined ) => void ) [ ] ;
1504
+
1505
+ export type InstanceChangeEvent = "change" ;
1506
+ export type InstanceDisposeEvent = "dispose" ;
1507
+ export type InstanceCacheChangeEvent = "cache-change" ;
1508
+
1509
+ export type InstanceEventType = InstanceChangeEvent |
1510
+ InstanceDisposeEvent |
1511
+ InstanceCacheChangeEvent ;
1512
+
1350
1513
export type AsyncStateSubscribeProps < T , E , R > = {
1351
1514
key ?: string ,
1352
1515
flags ?: number ,
1353
1516
origin ?: number ,
1354
1517
cb ( s : State < T , E , R > ) : void ,
1355
1518
}
1356
1519
1520
+ export type InstanceEvents < T , E , R > = {
1521
+ change ?: InstanceChangeEventHandlerType < T , E , R > ,
1522
+ dispose ?: InstanceDisposeEventHandlerType < T , E , R > ,
1523
+ [ 'cache-change' ] ?: InstanceCacheChangeEventHandlerType < T , E , R > ,
1524
+ }
1525
+
1357
1526
export interface StateInterface < T , E = any , R = any > extends BaseSource < T , E , R > {
1358
1527
// identity
1359
1528
version : number ,
@@ -1389,6 +1558,8 @@ export interface StateInterface<T, E = any, R = any> extends BaseSource<T, E, R>
1389
1558
// cache
1390
1559
cache ?: Record < string , CachedState < T , E , R > > | null ,
1391
1560
1561
+ events ?: InstanceEvents < T , E , R > ;
1562
+
1392
1563
// dev properties
1393
1564
journal ?: any [ ] , // for devtools, dev only
1394
1565
@@ -1415,7 +1586,9 @@ export interface StateInterface<T, E = any, R = any> extends BaseSource<T, E, R>
1415
1586
) ,
1416
1587
1417
1588
run (
1418
- createProducerEffects : ProducerEffectsCreator < T , E , R > , ...args : any [ ] ) : AbortFn ,
1589
+ createProducerEffects : ProducerEffectsCreator < T , E , R > ,
1590
+ ...args : any [ ]
1591
+ ) : AbortFn ,
1419
1592
1420
1593
runp (
1421
1594
createProducerEffects : ProducerEffectsCreator < T , E , R > ,
@@ -1635,7 +1808,8 @@ export interface StateBuilderInterface {
1635
1808
pending : < T > ( props : ProducerSavedProps < T > ) => PendingState < T > ,
1636
1809
success : < T > ( data : T , props : ProducerSavedProps < T > | null ) => SuccessState < T > ,
1637
1810
error : < T , E > ( data : any , props : ProducerSavedProps < T > ) => ErrorState < T , E > ,
1638
- aborted : < T , E , R > ( reason : any , props : ProducerSavedProps < T > ) => AbortedState < T , E , R > ,
1811
+ aborted : < T , E , R > (
1812
+ reason : any , props : ProducerSavedProps < T > ) => AbortedState < T , E , R > ,
1639
1813
}
1640
1814
1641
1815
export type ForkConfig = {
@@ -1644,7 +1818,9 @@ export type ForkConfig = {
1644
1818
keepCache ?: boolean ,
1645
1819
}
1646
1820
1647
- export type AsyncStateKeyOrSource < T , E = any , R = any > = string | Source < T , E , R > ;
1821
+ export type AsyncStateKeyOrSource < T , E = any , R = any > =
1822
+ string
1823
+ | Source < T , E , R > ;
1648
1824
1649
1825
export interface ProducerEffects {
1650
1826
run : < T , E , R > (
@@ -1658,12 +1834,16 @@ export interface ProducerEffects {
1658
1834
) => Promise < State < T , E , R > > | undefined ,
1659
1835
1660
1836
select : < T , E , R > (
1661
- input : AsyncStateKeyOrSource < T , E , R > , lane ?: string ) => State < T , E , R > | undefined ,
1837
+ input : AsyncStateKeyOrSource < T , E , R > ,
1838
+ lane ?: string
1839
+ ) => State < T , E , R > | undefined ,
1662
1840
}
1663
1841
1664
1842
export type ProducerEffectsCreator < T , E , R > = ( props : ProducerProps < T , E , R > ) => ProducerEffects ;
1665
1843
1666
- export type ProducerRunInput < T , E = any , R = any > = AsyncStateKeyOrSource < T , E , R > | Producer < T , E , R > ;
1844
+ export type ProducerRunInput < T , E = any , R = any > =
1845
+ AsyncStateKeyOrSource < T , E , R >
1846
+ | Producer < T , E , R > ;
1667
1847
1668
1848
export type ProducerRunConfig = {
1669
1849
lane ?: string ,
0 commit comments