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