mobx
Version:
Simple, scalable state management.
96 lines (95 loc) • 3.82 kB
TypeScript
import { CaughtException, IDerivation, IDerivationState, IEqualsComparer, IObservable, IValueDidChange, Lambda, TraceMode } from "../internal";
export interface IComputedValue<T> {
get(): T;
set(value: T): void;
observe(listener: (change: IValueDidChange<T>) => void, fireImmediately?: boolean): Lambda;
}
export interface IComputedValueOptions<T> {
get?: () => T;
set?: (value: T) => void;
name?: string;
equals?: IEqualsComparer<T>;
context?: any;
requiresReaction?: boolean;
keepAlive?: boolean;
}
/**
* A node in the state dependency root that observes other nodes, and can be observed itself.
*
* ComputedValue will remember the result of the computation for the duration of the batch, or
* while being observed.
*
* During this time it will recompute only when one of its direct dependencies changed,
* but only when it is being accessed with `ComputedValue.get()`.
*
* Implementation description:
* 1. First time it's being accessed it will compute and remember result
* give back remembered result until 2. happens
* 2. First time any deep dependency change, propagate POSSIBLY_STALE to all observers, wait for 3.
* 3. When it's being accessed, recompute if any shallow dependency changed.
* if result changed: propagate STALE to all observers, that were POSSIBLY_STALE from the last step.
* go to step 2. either way
*
* If at any point it's outside batch and it isn't observed: reset everything and go to 1.
*/
export declare class ComputedValue<T> implements IObservable, IComputedValue<T>, IDerivation {
dependenciesState: IDerivationState;
observing: IObservable[];
newObserving: null;
isBeingObserved: boolean;
isPendingUnobservation: boolean;
observers: Set<any>;
diffValue: number;
runId: number;
lastAccessedBy: number;
lowestObserverState: IDerivationState;
unboundDepsCount: number;
__mapid: string;
protected value: T | undefined | CaughtException;
name: string;
triggeredBy?: string;
isComputing: boolean;
isRunningSetter: boolean;
derivation: () => T;
setter?: (value: T) => void;
isTracing: TraceMode;
scope: Object | undefined;
private equals;
private requiresReaction;
private keepAlive;
/**
* Create a new computed value based on a function expression.
*
* The `name` property is for debug purposes only.
*
* The `equals` property specifies the comparer function to use to determine if a newly produced
* value differs from the previous value. Two comparers are provided in the library; `defaultComparer`
* compares based on identity comparison (===), and `structualComparer` deeply compares the structure.
* Structural comparison can be convenient if you always produce a new aggregated object and
* don't want to notify observers if it is structurally the same.
* This is useful for working with vectors, mouse coordinates etc.
*/
constructor(options: IComputedValueOptions<T>);
onBecomeStale(): void;
onBecomeObservedListeners: Set<Lambda> | undefined;
onBecomeUnobservedListeners: Set<Lambda> | undefined;
onBecomeObserved(): void;
onBecomeUnobserved(): void;
/**
* Returns the current value of this computed value.
* Will evaluate its computation first if needed.
*/
get(): T;
peek(): T;
set(value: T): void;
private trackAndCompute;
computeValue(track: boolean): T | CaughtException;
suspend(): void;
observe(listener: (change: IValueDidChange<T>) => void, fireImmediately?: boolean): Lambda;
warnAboutUntrackedRead(): void;
toJSON(): T;
toString(): string;
valueOf(): T;
[Symbol.toPrimitive](): T;
}
export declare const isComputedValue: (x: any) => x is ComputedValue<{}>;