UNPKG

opendash

Version:

open.DASH data visualization framework

74 lines (59 loc) 1.72 kB
import produce from "immer"; type Selector<T, ReturnType> = (state: T) => ReturnType; type SubscriptionCallback<T> = () => void; type ProducerCallback<T> = (currentState: T) => T | void; export class Store<T> { private _state: T; private watcher = new Set<SubscriptionCallback<T>>(); private selectorCache = new Map<Selector<T, any>, any>(); constructor(initialState: T) { this._state = initialState; } state(): T { return this._state; } select<ReturnType>(selector: Selector<T, ReturnType>): ReturnType { return selector(this._state); } update(callbackOrState: T | ProducerCallback<T>): void { if (typeof callbackOrState === "function") { this._state = produce( this._state, callbackOrState as ProducerCallback<T> ) as T; } else { this._state = callbackOrState; } this.watcher.forEach(callback => { try { callback(); } catch (error) { console.error("Error in Store subscription callback:", error); } }); } subscribe(callback: SubscriptionCallback<T>) { this.watcher.add(callback); return () => { this.watcher.delete(callback); }; } subscribeSelection( selector: Selector<T, any>, callback: SubscriptionCallback<T> ) { const selectorCallback = () => { const cache = this.selectorCache.get(selector); const selection = selector(this._state); if (!cache || cache !== selection) { this.selectorCache.set(selector, selection); callback(); } }; this.watcher.add(selectorCallback); return () => { this.watcher.delete(selectorCallback); this.selectorCache.delete(selector); }; } }