1
+ // ----------------------------------------------------------------
2
+ // Vue 3 Reactivity
3
+ // Marc Backes (@themarcba)
4
+ // ----------------------------------------------------------------
5
+
6
+ let activeEffect : ( ( ) => void ) | null = null ;
7
+ const targetMap = new WeakMap < object , Map < any , Set < ( ) => void > > > ( ) ;
8
+
9
+ // Register an effect
10
+ function track ( target : object , key : any ) {
11
+ // Get depsMap from targetMap
12
+ let depsMap = targetMap . get ( target ) ;
13
+ if ( ! depsMap ) {
14
+ // new depsMap if it doesn't exist yet
15
+ depsMap = new Map ( ) ;
16
+ targetMap . set ( target , depsMap ) ;
17
+ }
18
+
19
+ // Get dep from depsMap
20
+ let dep = depsMap . get ( key ) ;
21
+ if ( ! dep ) {
22
+ // new dep if it doesn't exist yet
23
+ dep = new Set ( ) ;
24
+ depsMap . set ( key , dep ) ;
25
+ }
26
+
27
+ // Add effect
28
+ if ( activeEffect ) dep . add ( activeEffect ) ;
29
+ }
30
+
31
+ // Execute all registered effects for the target/key combination
32
+ function trigger ( target : object , key : any ) {
33
+ // Get depsMap from targetMap
34
+ const depsMap = targetMap . get ( target ) ;
35
+ // If there is no depsMap, no need to resume
36
+ if ( ! depsMap ) return ;
37
+
38
+ // Get dep from depsMap
39
+ const dep = depsMap . get ( key ) ;
40
+ // If there is no dep, no need to resume
41
+ if ( ! dep ) return ;
42
+
43
+ // Execute all effects
44
+ dep . forEach ( ( effect ) => effect ( ) ) ;
45
+ }
46
+
47
+ // Makes an object "reactive". Changes will be triggered once the property is tracked
48
+ function reactive < T extends object > ( target : T ) : T {
49
+ const handler : ProxyHandler < T > = {
50
+ // Intercept getter
51
+ get ( target , key , receiver ) {
52
+ const result = Reflect . get ( target , key , receiver ) ;
53
+ track ( target , key ) ;
54
+ return result ;
55
+ } ,
56
+ // Intercept setter
57
+ set ( target , key , value , receiver ) {
58
+ const result = Reflect . set ( target , key , value , receiver ) ;
59
+ trigger ( target , key ) ; // trigger a change in the target
60
+ return result ;
61
+ } ,
62
+ } ;
63
+
64
+ return new Proxy ( target , handler ) ;
65
+ }
66
+
67
+ // Watcher
68
+ function effect ( fn : ( ) => void ) {
69
+ activeEffect = fn ;
70
+ // Only execute when there is an activeEffect
71
+ if ( activeEffect ) activeEffect ( ) ;
72
+ activeEffect = null ;
73
+
74
+ // Return the function for easier cleanup
75
+ return fn ;
76
+
77
+
78
+ }
79
+
80
+ // function stop(effect: () => void) {
81
+ // for (const [target, depsMap] of targetMap) {
82
+ // for (const depSet of depsMap.values()) {
83
+ // depSet.delete(effect);
84
+ // }
85
+ // }
86
+ // }
87
+
88
+ export { reactive , effect } ;
0 commit comments