Files
djledda-web/app/reactivity.ts
Daniel Ledda bcb820f35e nice
2024-10-31 23:46:23 +01:00

75 lines
1.6 KiB
TypeScript

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();
}
}