@msom/reaction
Version:
@msom/reaction
77 lines (71 loc) • 1.95 kB
text/typescript
import { getGlobalData } from "@msom/common";
import { IObserver, Reaction, $REACTION, createReaction } from "../Reaction";
export type ComputedOption<T> = {
method: () => T;
equal?: (oldValue: T, newValue: T) => boolean;
};
export class Computed<T extends unknown = unknown> implements IObserver {
private declare dirty: boolean;
private declare cache: T;
private declare handles: Set<Reaction>;
private declare equal: (oldValue: T, newValue: T) => boolean;
private declare method: () => T;
private declare subReaction: Reaction | undefined;
constructor(props: ComputedOption<T>) {
Object.assign(this, props);
this.dirty = true;
}
track() {
const running = getGlobalData("@msom/reaction") as $REACTION;
if (running?.tracking) {
running.tracking(this);
}
}
get(): T {
this.track();
if (!this.dirty && typeof this.cache !== undefined) {
return this.cache;
} else {
this.compute();
return this.cache;
}
}
private compute() {
const { method } = this;
if (!method) {
return;
}
this.subReaction?.destroy();
// 将运行method收集到的依赖和computed的响应关联
this.subReaction = createReaction(
() => {
this.cache = method();
this.dirty = false;
},
() => {
this.notify();
}
);
}
notify(): void {
this.dirty = true;
const handles = [...this.handles];
for (const reaction of handles) {
reaction.notify();
}
}
addReaction(reaction: Reaction): void {
this.handles.add(reaction);
}
removeReaction(reaction: Reaction): void {
this.handles.delete(reaction);
}
destroy() {
this.dirty = true;
this.subReaction?.destroy();
this.subReaction = undefined;
this.handles.forEach((reaction) => {
reaction.removeObserver(this);
});
}
}