-
Notifications
You must be signed in to change notification settings - Fork 3
/
reactivity.js
101 lines (90 loc) · 2.51 KB
/
reactivity.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// ----------------------------------------------------------------
// Vue 3 Reactivity
// Marc Backes (@themarcba)
// ----------------------------------------------------------------
let activeEffect = null
let targetMap = new WeakMap()
// Register an effect
function track(target, key) {
// Get depsMap from targetMap
let depsMap = targetMap.get(target)
if (!depsMap) {
// new depsMap if it doesn't exist yet
depsMap = new Map()
targetMap.set(target, depsMap)
}
// Get dep from depsMap
let dep = depsMap.get(key)
if (!dep) {
// new dep if it doesn't exist yet
dep = new Set()
depsMap.set(key, dep)
}
// Add effect
if (activeEffect) dep.add(activeEffect)
}
// Execute all registered effects for the target/key combination
function trigger(target, key) {
// Get depsMap from targetMap
let depsMap = targetMap.get(target)
if (!depsMap) {
// If there is no depsMap, no need to resume
return
}
// Get dep from depsMap
let dep = depsMap.get(key)
if (!dep) {
// If there is no dep, no need to resume
return
}
// Execute all effects
dep.forEach(effect => effect())
}
// Makes an object "reactive". Changes will be triggered, once the property is tracked
function reactive(target) {
const handler = {
// Intercept getter
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
track(target, key) //track changes for the key in the target
return result
},
// Intercept setter
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver)
trigger(target, key) // trigger a change in the target
return result
},
}
return new Proxy(target, handler)
}
// Watcher
function effect(fn) {
activeEffect = fn
// Only execute when there is an activeEffect
if (activeEffect) activeEffect()
activeEffect = null
}
// The ref class is a reactive object with a single value (called "value")
function ref(raw) {
let r = {
// Intercept getter
get value() {
track(r, 'value')
return raw
},
// Intercept setter
set value(newValue) {
raw = newValue
trigger(r, 'value')
},
}
return r
}
// Computed property
function computed(getter) {
let result = ref()
effect(() => {
result.value = getter()
})
}