-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
reactive.ts
80 lines (69 loc) · 1.63 KB
/
reactive.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
type On<T> = (value: T) => void;
type Off = () => void;
interface Subscription<T> {
emit: On<T>;
off: Off;
}
interface Options {
emitOnSubscribe?: boolean; // if set, emit right on subscribe (like rxjs BehaviorSubject)
emitEqual?: boolean; // if set, emit when new value is equal to the old one
}
export class Reactive<T> {
private initialValue: T;
private value: T;
private id: number;
private options: Options;
private subscriptions: Map<number, Subscription<T>>;
constructor(value?: T, options?: Options) {
this.id = 0;
if (value !== void 0) {
this.value = value;
this.initialValue = value;
}
this.options = options || {};
this.subscriptions = new Map();
}
set(value: T): void {
if (this.value === value && !this.options.emitEqual) {
return;
}
this.value = value;
for (const [, sub] of this.subscriptions) {
sub.emit(value);
if (this.value !== value) {
break;
}
}
}
get(): T {
return this.value;
}
on(func: On<T>): Off {
const id = this.id++;
const subscription: Subscription<T> = {
emit: func,
off: () => {
subscription.emit = () => null;
this.subscriptions.delete(id);
}
};
this.subscriptions.set(id, subscription);
if (this.options.emitOnSubscribe) {
subscription.emit(this.value);
}
return () => subscription.off();
}
once(func: On<T>): Off {
const off = this.on(v => {
off();
func(v);
});
return off;
}
reset(): void {
this.set(this.initialValue);
}
dispose(): void {
this.subscriptions.forEach(sub => sub.off());
}
}