2
2
/* === Internal === */
3
3
// hold the currently active effect
4
4
let active ;
5
+ /**
6
+ * Run all effects in the provided set
7
+ *
8
+ * @param {Set<UIEffects> } effects
9
+ */
10
+ const autorun = ( effects ) => {
11
+ for ( const effect of effects )
12
+ effect . run ( ) ;
13
+ } ;
5
14
/* === Exported functions === */
6
15
/**
7
16
* Check if a given variable is a function
@@ -35,10 +44,7 @@ const cause = (value) => {
35
44
value = isFunction ( updater ) && ! isState ( updater )
36
45
? updater ( old )
37
46
: updater ;
38
- if ( ! Object . is ( value , old ) ) {
39
- for ( const effect of state . effects )
40
- effect ( ) ;
41
- }
47
+ ! Object . is ( value , old ) && autorun ( state . effects ) ;
42
48
} ;
43
49
return state ;
44
50
} ;
@@ -47,16 +53,28 @@ const cause = (value) => {
47
53
*
48
54
* @since 0.1.0
49
55
* @param {() => any } fn - existing state to derive from
50
- * @returns {() => any } derived state
56
+ * @param {boolean } [memo=false] - whether to use memoization
57
+ * @returns {UIComputed<any> } derived state
51
58
*/
52
- const derive = ( fn ) => {
59
+ const derive = ( fn , memo = false ) => {
60
+ let value ;
61
+ let dirty = true ;
53
62
const computed = ( ) => {
63
+ active && computed . effects . add ( active ) ;
64
+ if ( memo && ! dirty )
65
+ return value ;
54
66
const prev = active ;
55
67
active = computed ;
56
- const value = fn ( ) ;
68
+ value = fn ( ) ;
69
+ dirty = false ;
57
70
active = prev ;
58
71
return value ;
59
72
} ;
73
+ computed . effects = new Set ( ) ; // set of listeners
74
+ computed . run = ( ) => {
75
+ dirty = true ;
76
+ memo && autorun ( computed . effects ) ;
77
+ } ;
60
78
return computed ;
61
79
} ;
62
80
/**
@@ -74,15 +92,14 @@ const effect = (fn) => {
74
92
! targets . has ( element ) && targets . set ( element , new Set ( ) ) ;
75
93
targets . get ( element ) . add ( domFn ) ;
76
94
} ) ;
95
+ for ( const domFns of targets . values ( ) ) {
96
+ for ( const domFn of domFns )
97
+ domFn ( ) ;
98
+ }
77
99
active = prev ;
78
- ( targets . size || cleanup ) && queueMicrotask ( ( ) => {
79
- for ( const domFns of targets . values ( ) ) {
80
- for ( const domFn of domFns )
81
- domFn ( ) ;
82
- }
83
- isFunction ( cleanup ) && cleanup ( ) ;
84
- } ) ;
100
+ isFunction ( cleanup ) && queueMicrotask ( cleanup ) ;
85
101
} ;
102
+ next . run = ( ) => next ( ) ;
86
103
next . targets = targets ;
87
104
next ( ) ;
88
105
} ;
0 commit comments