-
Notifications
You must be signed in to change notification settings - Fork 2
/
signal.ts
81 lines (66 loc) · 1.55 KB
/
signal.ts
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
// A signal implementation featuring effects, signals, memos, caching,
// `untrack`, `batch`, and unsubscribing.
let currentEffect: (() => void) | undefined
let currentBatch: Set<() => void> | undefined
function safeCall(fn: () => void) {
try {
fn()
} catch {}
}
export function createEffect(effect: () => void) {
function effectFn() {
const parentEffect = currentEffect
try {
currentEffect = effectFn
effect()
} finally {
currentEffect = parentEffect
}
}
effectFn()
}
export type Signal<T> = [get: () => T, set: (value: T) => void]
export function createSignal<T>(value: T): Signal<T> {
const tracked = new Set<() => void>()
return [
() => {
if (currentEffect) {
tracked.add(currentEffect)
}
return value
},
(newValue) => {
value = newValue
if (currentBatch) {
tracked.forEach((fn) => currentBatch!.add(fn))
} else {
tracked.forEach(safeCall)
}
},
]
}
export function createMemo<T>(memo: () => T): () => T {
const [get, set] = createSignal<T>(null!)
createEffect(() => set(memo()))
return get
}
export function useUntrack<T>(get: () => T): T {
const parentEffect = currentEffect
try {
currentEffect = undefined
return get()
} finally {
currentEffect = parentEffect
}
}
export function useBatch<T>(get: () => T): T {
const parentBatch = currentBatch
currentBatch = new Set()
const batch = currentBatch
try {
return get()
} finally {
currentBatch = parentBatch
batch.forEach(safeCall)
}
}