nice
This commit is contained in:
74
app/reactivity.ts
Normal file
74
app/reactivity.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
const contextStack: Observer[] = [];
|
||||
|
||||
export class Observer<T = unknown> {
|
||||
private effect: () => T;
|
||||
|
||||
dependencies: Set<Observable> = new Set();
|
||||
|
||||
constructor(effect: { (): T }) {
|
||||
this.effect = effect;
|
||||
this.execute();
|
||||
}
|
||||
|
||||
execute() {
|
||||
this.cleanup();
|
||||
contextStack.push(this);
|
||||
try {
|
||||
this.effect();
|
||||
} finally {
|
||||
contextStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
for (const dep of this.dependencies.values()) {
|
||||
dep.observers.delete(this);
|
||||
}
|
||||
this.dependencies.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export class Observable<T = unknown> {
|
||||
private value: T;
|
||||
|
||||
observers: Set<Observer> = new Set();
|
||||
|
||||
constructor(init: T) {
|
||||
this.value = init;
|
||||
}
|
||||
|
||||
get() {
|
||||
const activeObserver = contextStack[contextStack.length - 1];
|
||||
if (activeObserver) {
|
||||
this.observers.add(activeObserver);
|
||||
activeObserver.dependencies.add(this);
|
||||
}
|
||||
return this.value;
|
||||
}
|
||||
|
||||
set(next: T) {
|
||||
this.value = next;
|
||||
for (const observer of Array.from(this.observers.values())) {
|
||||
observer.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Mapping<T extends unknown> {
|
||||
private observable: Observable<T>;
|
||||
|
||||
private observer: Observer<T>;
|
||||
|
||||
constructor(mapping: { (): T }) {
|
||||
this.observable = new Observable(undefined as T);
|
||||
this.observer = new Observer(() => {
|
||||
const result = mapping();
|
||||
this.observable.set(result);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
get() {
|
||||
return this.observable.get();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user