-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgofer.go
89 lines (73 loc) · 1.47 KB
/
gofer.go
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
package gofer
import (
"reflect"
)
type effect func()
var currentActiveEffect effect
type dep struct {
subscribers map[uintptr]effect
}
func newDep() *dep {
return &dep{subscribers: make(map[uintptr]effect)}
}
func (d *dep) track(update effect) {
key := reflect.ValueOf(update).Pointer()
d.subscribers[key] = currentActiveEffect
}
func (d *dep) trigger() {
for _, effect := range d.subscribers {
if effect != nil {
effect()
}
}
}
/*
RefImpl (ref) is a reactive primitive that can be read and written onto
*/
type RefImpl[T any] struct {
dep *dep
value T
}
func Ref[T any](initialValue T) *RefImpl[T] {
return &RefImpl[T]{
dep: newDep(),
value: initialValue,
}
}
func (r *RefImpl[T]) GetValue() T {
r.dep.track(currentActiveEffect)
return r.value
}
func (r *RefImpl[T]) SetValue(newValue T) {
r.value = newValue
r.dep.trigger()
}
/*
computed is a ref that is computed by a getter
*/
type computed[T any] struct {
dep *dep
compute func() T
}
func Computed[T any](computedValue func() T) *computed[T] {
return &computed[T]{
dep: newDep(),
compute: computedValue,
}
}
func (c *computed[T]) GetValue() T {
c.dep.track(currentActiveEffect)
return c.compute()
}
/*
Runs a function immediately while reactively tracking its dependencies
and re-runs it whenever the dependencies are changed.
*/
func WatchEffect(update effect) {
var wrappedUpdate func()
wrappedUpdate = func() {
currentActiveEffect = wrappedUpdate
update()
}
wrappedUpdate()
}