export type HookFn = (e?: TSnapshot) => void; export interface HookFilter { fn: HookFn; } /** * Simple React hookable store with manual change notifications */ export abstract class ExternalStore { #hooks: Array> = []; #snapshot: TSnapshot = {} as TSnapshot; #changed = true; hook(fn: HookFn) { this.#hooks.push({ fn, }); return () => { const idx = this.#hooks.findIndex(a => a.fn === fn); if (idx >= 0) { this.#hooks.splice(idx, 1); } }; } snapshot(p?: any) { if (this.#changed) { this.#snapshot = this.takeSnapshot(p); this.#changed = false; } return this.#snapshot; } protected notifyChange(sn?: TSnapshot) { this.#changed = true; if (this.#hooks.length > 0) { this.#hooks.forEach(h => h.fn(sn)); } } abstract takeSnapshot(p?: any): TSnapshot; }