UNPKG

computed-async-mobx

Version:

Define a computed by returning a Promise

137 lines (116 loc) 3.73 kB
import { computed } from "mobx" import { promisedComputedInternal, PromisedComputedValue } from "./promisedComputed"; import { throttledComputed } from "./throttledComputed" import { Getter } from "./Getter"; /** * DEPRECATED * * The type returned by the `computedAsync` function. Represents the current `value`. Accessing * the value inside a reaction will automatically listen to it, just like an `observable` or * `computed`. The `busy` property is `true` when the asynchronous function is currently running. */ export interface ComputedAsyncValue<T> { /** The current value (observable) */ readonly value: T; /** True if an async evaluation is in progress */ readonly busy: boolean; /** True if Promise was rejected */ readonly failed: boolean; /** The error from the rejected promise, or undefined */ readonly error: any; } export interface ComputedAsyncOptions<T> { readonly init: T; readonly fetch: () => PromiseLike<T> | T; readonly delay?: number; readonly revert?: boolean; readonly name?: string; readonly error?: (error: any) => T; readonly rethrow?: boolean; } class ComputedAsync<T> implements ComputedAsyncValue<T> { private computation: Getter<PromiseLike<T> | T>; private promised: PromisedComputedValue<T> private lastValue: T | undefined; constructor(private options: ComputedAsyncOptions<T>) { if (options.delay) { this.computation = throttledComputed(options.fetch, options.delay); } else { this.computation = computed(options.fetch); } this.promised = promisedComputedInternal<T>(options.init, () => this.computation.get()); } get busy() { return this.promised.busy; } @computed get failed() { try { this.promised.get(); return false; } catch (x) { return true; } } @computed get error() { try { this.promised.get(); return undefined; } catch (x) { return x; } } private initializedValue() { this.lastValue = this.promised.get(); return this.lastValue; // this.lastValue === undefined ? this.options.init : this.lastValue; } @computed get value(): T { if (this.promised.busy && this.options.revert) { return this.options.init; } if (this.options.rethrow) { return this.initializedValue(); } try { return this.initializedValue(); } catch (x) { if (this.options.error) { try { return this.options.error(x); } catch (x) { console.error(x); } } return this.lastValue === undefined ? this.options.init : this.lastValue; } } } /** * DEPRECATED - prefer `asyncComputed`, see https://github.com/danielearwicker/computed-async-mobx */ export function computedAsync<T>( init: T, fetch: () => PromiseLike<T> | T, delay?: number): ComputedAsyncValue<T>; /** * DEPRECATED - prefer `asyncComputed`, see https://github.com/danielearwicker/computed-async-mobx */ export function computedAsync<T>( options: ComputedAsyncOptions<T> ): ComputedAsyncValue<T>; export function computedAsync<T>( init: T | ComputedAsyncOptions<T>, fetch?: () => PromiseLike<T> | T, delay?: number ) { if (arguments.length === 1) { return new ComputedAsync<T>(init as ComputedAsyncOptions<T>); } return new ComputedAsync<T>({ init: init as T, fetch: fetch!, delay }); }