mobx-utils

  • Version 6.1.0
  • Published
  • 292 kB
  • No dependencies
  • MIT license

Install

npm i mobx-utils
yarn add mobx-utils
pnpm add mobx-utils

Overview

Utility functions and common patterns for MobX

Index

Variables

variable FULFILLED

const FULFILLED: string;

    variable PENDING

    const PENDING: string;

      variable REJECTED

      const REJECTED: string;

        Functions

        function addHiddenProp

        addHiddenProp: (object: any, propName: string, value: any) => void;

          function chunkProcessor

          chunkProcessor: <T>(
          observableArray: T[],
          processor: (item: T[]) => void,
          debounce?: number,
          maxChunkSize?: number
          ) => IDisposer;
          • chunkProcessor takes an observable array, observes it and calls processor once for a chunk of items added to the observable array, optionally deboucing the action. The maximum chunk size can be limited by number. This allows both, splitting larger into smaller chunks or (when debounced) combining smaller chunks and/or single items into reasonable chunks of work.

            Parameter observableArray

            observable array instance to track

            Parameter processor

            action to call per item

            Parameter debounce

            optional debounce time in ms. With debounce 0 the processor will run synchronously

            Parameter maxChunkSize

            optionally do not call on full array but smaller chunks. With 0 it will process the full array.

            Returns

            {IDisposer} stops the processor

            Example 1

            const trackedActions = observable([]) const stop = chunkProcessor(trackedActions, chunkOfMax10Items => { sendTrackedActionsToServer(chunkOfMax10Items); }, 100, 10)

            // usage: trackedActions.push("scrolled") trackedActions.push("hoveredButton") // when both pushes happen within 100ms, there will be only one call to server

          function computedFn

          computedFn: <T extends (...args: any[]) => any>(
          fn: T,
          keepAliveOrOptions?: IComputedFnOptions<T> | boolean
          ) => T;
          • computedFn takes a function with an arbitrary amount of arguments, and memoizes the output of the function based on the arguments passed in.

            computedFn(fn) returns a function with the very same signature. There is no limit on the amount of arguments that is accepted. However, the amount of arguments must be constant and default arguments are not supported.

            By default the output of a function call will only be memoized as long as the output is being observed.

            The function passes into computedFn should be pure, not be an action and only be relying on observables.

            Setting keepAlive to true will cause the output to be forcefully cached forever. Note that this might introduce memory leaks!

            Parameter fn

            Parameter keepAliveOrOptions

            Example 1

            const store = observable({ a: 1, b: 2, c: 3, m: computedFn(function(x) { return this.a * this.b * x }) })

            const d = autorun(() => { // store.m(3) will be cached as long as this autorun is running console.log(store.m(3) * store.c) })

          function createTransformer

          createTransformer: {
          <A, B>(
          transformer: ITransformer<A, B>,
          onCleanup?: ITransformerCleanup<A, B>
          ): ITransformer<A, B>;
          <A, B>(
          transformer: ITransformer<A, B>,
          arg2?: ITransformerParams<A, B>
          ): ITransformer<A, B>;
          };

            function createViewModel

            createViewModel: <T>(model: T) => T & IViewModel<T>;
            • createViewModel takes an object with observable properties (model) and wraps a viewmodel around it. The viewmodel proxies all enumerable properties of the original model with the following behavior: - as long as no new value has been assigned to the viewmodel property, the original property will be returned. - any future change in the model will be visible in the viewmodel as well unless the viewmodel property was dirty at the time of the attempted change. - once a new value has been assigned to a property of the viewmodel, that value will be returned during a read of that property in the future. However, the original model remain untouched until submit() is called.

              The viewmodel exposes the following additional methods, besides all the enumerable properties of the model: - submit(): copies all the values of the viewmodel to the model and resets the state - reset(): resets the state of the viewmodel, abandoning all local modifications - resetProperty(propName): resets the specified property of the viewmodel - isDirty: observable property indicating if the viewModel contains any modifications - isPropertyDirty(propName): returns true if the specified property is dirty - changedValues: returns a key / value map with the properties that have been changed in the model so far - model: The original model object for which this viewModel was created

              You may use observable arrays, maps and objects with createViewModel but keep in mind to assign fresh instances of those to the viewmodel's properties, otherwise you would end up modifying the properties of the original model. Note that if you read a non-dirty property, viewmodel only proxies the read to the model. You therefore need to assign a fresh instance not only the first time you make the assignment but also after calling reset() or submit().

              Parameter model

              Returns

              {(T & IViewModel)} ```

              Example 1

              class Todo { @observable title = "Test" }

              const model = new Todo() const viewModel = createViewModel(model);

              autorun(() => console.log(viewModel.model.title, ",", viewModel.title)) // prints "Test, Test" model.title = "Get coffee" // prints "Get coffee, Get coffee", viewModel just proxies to model viewModel.title = "Get tea" // prints "Get coffee, Get tea", viewModel's title is now dirty, and the local value will be printed viewModel.submit() // prints "Get tea, Get tea", changes submitted from the viewModel to the model, viewModel is proxying again viewModel.title = "Get cookie" // prints "Get tea, Get cookie" // viewModel has diverged again viewModel.reset() // prints "Get tea, Get tea", changes of the viewModel have been abandoned

            function deepObserve

            deepObserve: <T = any>(
            target: T,
            listener: (change: IChange, path: string, root: T) => void
            ) => IDisposer;
            • Given an object, deeply observes the given object. It is like observe from mobx, but applied recursively, including all future children.

              Note that the given object cannot ever contain cycles and should be a tree.

              As benefit: path and root will be provided in the callback, so the signature of the listener is (change, path, root) => void

              The returned disposer can be invoked to clean up the listener

              deepObserve cannot be used on computed values.

              Example 1

              const disposer = deepObserve(target, (change, path) => { console.dir(change) })

            function expr

            expr: <T>(expr: () => T) => T;
            • expr can be used to create temporary computed values inside computed values. Nesting computed values is useful to create cheap computations in order to prevent expensive computations from needing to run. In the following example the expression prevents that a component is rerender _each time_ the selection changes; instead it will only rerenders when the current todo is (de)selected.

              expr(func) is an alias for computed(func).get(). Please note that the function given to expr is evaluated _twice_ in the scenario that the overall expression value changes. It is evaluated the first time when any observables it depends on change. It is evaluated a second time when a change in its value triggers the outer computed or reaction to evaluate, which recreates and reevaluates the expression.

              In the following example, the expression prevents the TodoView component from being re-rendered if the selection changes elsewhere. Instead, the component will only re-render when the relevant todo is (de)selected, which happens much less frequently.

              Example 1

              const TodoView = observer(({ todo, editorState }) => { const isSelected = mobxUtils.expr(() => editorState.selection === todo) return <div className={isSelected ? "todo todo-selected" : "todo"}>{todo.title} })

            function fail

            fail: (message: string) => never;

              function fromPromise

              fromPromise: typeof fromPromise;
              • fromPromise takes a Promise, extends it with 2 observable properties that track the status of the promise and returns it. The returned object has the following observable properties: - value: either the initial value, the value the Promise resolved to, or the value the Promise was rejected with. use .state if you need to be able to tell the difference. - state: one of "pending", "fulfilled" or "rejected"

                And the following methods: - case({fulfilled, rejected, pending}): maps over the result using the provided handlers, or returns undefined if a handler isn't available for the current promise state.

                The returned object implements PromiseLike<TValue>, so you can chain additional Promise handlers using then. You may also use it with await in async functions.

                Note that the status strings are available as constants: mobxUtils.PENDING, mobxUtils.REJECTED, mobxUtil.FULFILLED

                fromPromise takes an optional second argument, a previously created fromPromise based observable. This is useful to replace one promise based observable with another, without going back to an intermediate "pending" promise state while fetching data. For example:

                Parameter origPromise

                The promise which will be observed

                Parameter oldPromise

                The previously observed promise

                Returns

                origPromise with added properties and methods described above.

                Example 1

                @observer class SearchResults extends React.Component { @observable.ref searchResults

                componentDidUpdate(nextProps) { if (nextProps.query !== this.props.query) this.searchResults = fromPromise( window.fetch("/search?q=" + nextProps.query), // by passing, we won't render a pending state if we had a successful search query before // rather, we will keep showing the previous search results, until the new promise resolves (or rejects) this.searchResults ) }

                render() { return this.searchResults.case({ pending: (staleValue) => { return staleValue || "searching" // <- value might set to previous results while the promise is still pending }, fulfilled: (value) => { return value // the fresh results }, rejected: (error) => { return "Oops: " + error } }) } }

                Observable promises can be created immediately in a certain state using fromPromise.reject(reason) or fromPromise.resolve(value?). The main advantage of fromPromise.resolve(value) over fromPromise(Promise.resolve(value)) is that the first _synchronously_ starts in the desired state.

                It is possible to directly create a promise using a resolve, reject function: fromPromise((resolve, reject) => setTimeout(() => resolve(true), 1000))

                Example 2

                const fetchResult = fromPromise(fetch("http://someurl"))

                // combine with when.. when( () => fetchResult.state !== "pending", () => { console.log("Got ", fetchResult.value) } )

                // or a mobx-react component.. const myComponent = observer(({ fetchResult }) => { switch(fetchResult.state) { case "pending": return Loading... case "rejected": return Ooops... {fetchResult.value} case "fulfilled": return Gotcha: {fetchResult.value} } })

                // or using the case method instead of switch:

                const myComponent = observer(({ fetchResult }) => fetchResult.case({ pending: () => Loading..., rejected: error => Ooops.. {error}, fulfilled: value => Gotcha: {value}, }))

                // chain additional handler(s) to the resolve/reject:

                fetchResult.then( (result) => doSomeTransformation(result), (rejectReason) => console.error('fetchResult was rejected, reason: ' + rejectReason) ).then( (transformedResult) => console.log('transformed fetchResult: ' + transformedResult) )

              function fromResource

              fromResource: {
              <T>(
              subscriber: (sink: (newValue: T) => void) => void,
              unsubscriber?: IDisposer
              ): IResource<T | undefined>;
              <T>(
              subscriber: (sink: (newValue: T) => void) => void,
              unsubscriber: IDisposer,
              initialValue: T
              ): IResource<T>;
              };

                function fromStream

                fromStream: {
                <T>(observable: IObservableStream<T>): IStreamListener<T | undefined>;
                <T, I>(observable: IObservableStream<T>, initialValue: I): IStreamListener<
                T | I
                >;
                };
                • Converts a subscribable, observable stream (TC 39 observable / RxJS stream) into an object which stores the current value (as current). The subscription can be cancelled through the dispose method. Takes an initial value as second optional argument

                  Example 1

                  const debouncedClickDelta = MobxUtils.fromStream(Rx.Observable.fromEvent(button, 'click') .throttleTime(1000) .map(event => event.clientX) .scan((count, clientX) => count + clientX, 0) )

                  autorun(() => { console.log("distance moved", debouncedClickDelta.current) })

                function getAllMethodsAndProperties

                getAllMethodsAndProperties: (x: any) => any;

                  function IDENTITY

                  IDENTITY: (_: any) => any;

                    function invariant

                    invariant: (cond: boolean, message?: string) => void;

                      function isPromiseBasedObservable

                      isPromiseBasedObservable: (value: any) => value is IPromiseBasedObservable<any>;
                      • Returns true if the provided value is a promise-based observable.

                        Parameter value

                        any

                        Returns

                        {boolean}

                      function keepAlive

                      keepAlive: {
                      (target: Object, property: string): IDisposer;
                      (computedValue: IComputedValue<any>): IDisposer;
                      };

                        function lazyObservable

                        lazyObservable: {
                        <T>(fetch: (sink: (newValue: T) => void) => void): ILazyObservable<
                        T | undefined
                        >;
                        <T>(
                        fetch: (sink: (newValue: T) => void) => void,
                        initialValue: T
                        ): ILazyObservable<T>;
                        };

                          function moveItem

                          moveItem: <T>(
                          target: IObservableArray<T>,
                          fromIndex: number,
                          toIndex: number
                          ) => IObservableArray<T> | undefined;
                          • Moves an item from one position to another, checking that the indexes given are within bounds.

                            Parameter target

                            Parameter fromIndex

                            Parameter toIndex

                            Returns

                            {ObservableArray}

                            Example 1

                            const source = observable([1, 2, 3]) moveItem(source, 0, 1) console.log(source.map(x => x)) // [2, 1, 3]

                          function NOOP

                          NOOP: () => void;

                            function now

                            now: (interval?: number | 'frame') => number;
                            • Returns the current date time as epoch number. The date time is read from an observable which is updated automatically after the given interval. So basically it treats time as an observable.

                              The function takes an interval as parameter, which indicates how often now() will return a new value. If no interval is given, it will update each second. If "frame" is specified, it will update each time a requestAnimationFrame is available.

                              Multiple clocks with the same interval will automatically be synchronized.

                              Countdown example: https://jsfiddle.net/mweststrate/na0qdmkw/

                              Parameter interval

                              interval in milliseconds about how often the interval should update

                              Returns

                              Example 1

                              const start = Date.now()

                              autorun(() => { console.log("Seconds elapsed: ", (mobxUtils.now() - start) / 1000) })

                            function queueProcessor

                            queueProcessor: <T>(
                            observableArray: T[],
                            processor: (item: T) => void,
                            debounce?: number
                            ) => IDisposer;
                            • queueProcessor takes an observable array, observes it and calls processor once for each item added to the observable array, optionally debouncing the action

                              Parameter observableArray

                              observable array instance to track

                              Parameter processor

                              action to call per item

                              Parameter debounce

                              optional debounce time in ms. With debounce 0 the processor will run synchronously

                              Returns

                              {IDisposer} stops the processor

                              Example 1

                              const pendingNotifications = observable([]) const stop = queueProcessor(pendingNotifications, msg => { // show Desktop notification new Notification(msg); })

                              // usage: pendingNotifications.push("test!")

                            function resetNowInternalState

                            resetNowInternalState: () => void;
                            • Disposes of all the internal Observables created by invocations of now().

                              The use case for this is to ensure that unit tests can run independent of each other. You should not call this in regular application code.

                              Example 1

                              afterEach(() => { utils.resetNowInternalState() })

                            function toStream

                            toStream: <T>(
                            expression: () => T,
                            fireImmediately?: boolean
                            ) => IObservableStream<T>;
                            • Converts an expression to an observable stream (a.k.a. TC 39 Observable / RxJS observable). The provided expression is tracked by mobx as long as there are subscribers, automatically emitting when new values become available. The expressions respect (trans)actions.

                              Parameter expression

                              Parameter fireImmediately

                              (by default false)

                              Returns

                              {IObservableStream}

                              Example 1

                              const user = observable({ firstName: "C.S", lastName: "Lewis" })

                              Rx.Observable .from(mobxUtils.toStream(() => user.firstname + user.lastName)) .scan(nameChanges => nameChanges + 1, 0) .subscribe(nameChanges => console.log("Changed name ", nameChanges, "times"))

                              T

                            Classes

                            class ObservableGroupMap

                            class ObservableGroupMap<G, T> extends ObservableMap<G, IObservableArray<T>> {}
                            • Reactively sorts a base observable array into multiple observable arrays based on the value of a groupBy: (item: T) => G function.

                              This observes the individual computed groupBy values and only updates the source and dest arrays when there is an actual change, so this is far more efficient than, for example base.filter(i => groupBy(i) === 'we'). Call #dispose() to stop tracking.

                              No guarantees are made about the order of items in the grouped arrays.

                              The resulting map of arrays is read-only. clear(), set(), delete() are not supported and modifying the group arrays will lead to undefined behavior.

                              NB: ObservableGroupMap relies on Symbols. If you are targeting a platform which doesn't support these natively, you will need to provide a polyfill.

                              Parameter base

                              The array to sort into groups.

                              Parameter groupBy

                              The function used for grouping.

                              Parameter options

                              Object with properties: name: Debug name of this ObservableGroupMap. keyToName: Function to create the debug names of the observable group arrays.

                              Example 1

                              const slices = observable([ { day: "mo", hours: 12 }, { day: "tu", hours: 2 }, ]) const slicesByDay = new ObservableGroupMap(slices, (slice) => slice.day) autorun(() => console.log( slicesByDay.get("mo")?.length ?? 0, slicesByDay.get("we"))) // outputs 1, undefined slices[0].day = "we" // outputs 0, [{ day: "we", hours: 12 }]

                            constructor

                            constructor(
                            base: IObservableArray<T>,
                            groupBy: (x: T) => G,
                            { name, keyToName }?: { name?: string; keyToName?: (group: G) => string }
                            );

                              method clear

                              clear: () => void;

                                method delete

                                delete: (_key: G) => boolean;

                                  method dispose

                                  dispose: () => void;
                                  • Disposes all observers created during construction and removes state added to base array items.

                                  method set

                                  set: (_key: G, _value: IObservableArray<T>) => this;

                                    class ViewModel

                                    class ViewModel<T> implements IViewModel<T> {}

                                      constructor

                                      constructor(model: {});

                                        property changedValues

                                        readonly changedValues: Map<keyof T, T[keyof T]>;

                                          property isDirty

                                          readonly isDirty: boolean;

                                            property isPropertyDirty

                                            isPropertyDirty: (key: keyof T) => boolean;

                                              property localComputedValues

                                              localComputedValues: ObservableMap<keyof T, IComputedValue<T[keyof T]>>;

                                                property localValues

                                                localValues: ObservableMap<keyof T, T[keyof T]>;

                                                  property model

                                                  model: {};

                                                    method reset

                                                    reset: () => void;

                                                      method resetProperty

                                                      resetProperty: (key: keyof T) => void;

                                                        method submit

                                                        submit: () => void;

                                                          Interfaces

                                                          interface IBasePromiseBasedObservable

                                                          interface IBasePromiseBasedObservable<T> extends PromiseLike<T> {}

                                                            property isPromiseBasedObservable

                                                            isPromiseBasedObservable: true;

                                                              method case

                                                              case: <U>(handlers: CaseHandlers<U, T>, defaultFulfilled?: boolean) => U;

                                                                interface ILazyObservable

                                                                interface ILazyObservable<T> {}

                                                                  property pending

                                                                  pending: boolean;

                                                                    method current

                                                                    current: () => T;

                                                                      method refresh

                                                                      refresh: () => T;

                                                                        method reset

                                                                        reset: () => T;

                                                                          interface IObservableStream

                                                                          interface IObservableStream<T> {}

                                                                            method subscribe

                                                                            subscribe: {
                                                                            (observer?: IStreamObserver<T> | null): ISubscription;
                                                                            (observer?: (value: T) => void): ISubscription;
                                                                            };

                                                                              interface IResource

                                                                              interface IResource<T> {}

                                                                                method current

                                                                                current: () => T;

                                                                                  method dispose

                                                                                  dispose: () => void;

                                                                                    method isAlive

                                                                                    isAlive: () => boolean;

                                                                                      interface IStreamListener

                                                                                      interface IStreamListener<T> {}

                                                                                        property current

                                                                                        current: T;

                                                                                          method dispose

                                                                                          dispose: () => void;

                                                                                            interface IStreamObserver

                                                                                            interface IStreamObserver<T> {}

                                                                                              method complete

                                                                                              complete: () => void;

                                                                                                method error

                                                                                                error: (error: any) => void;

                                                                                                  method next

                                                                                                  next: (value: T) => void;

                                                                                                    interface ISubscription

                                                                                                    interface ISubscription {}

                                                                                                      method unsubscribe

                                                                                                      unsubscribe: () => void;

                                                                                                        interface IViewModel

                                                                                                        interface IViewModel<T> {}

                                                                                                          property changedValues

                                                                                                          changedValues: Map<keyof T, T[keyof T]>;

                                                                                                            property isDirty

                                                                                                            isDirty: boolean;

                                                                                                              property model

                                                                                                              model: T;

                                                                                                                method isPropertyDirty

                                                                                                                isPropertyDirty: (key: keyof T) => boolean;

                                                                                                                  method reset

                                                                                                                  reset: () => void;

                                                                                                                    method resetProperty

                                                                                                                    resetProperty: (key: keyof T) => void;

                                                                                                                      method submit

                                                                                                                      submit: () => void;

                                                                                                                        Type Aliases

                                                                                                                        type IDisposer

                                                                                                                        type IDisposer = () => void;

                                                                                                                          type IFulfilledPromise

                                                                                                                          type IFulfilledPromise<T> = {
                                                                                                                          readonly state: 'fulfilled';
                                                                                                                          readonly value: T;
                                                                                                                          };

                                                                                                                            type IPendingPromise

                                                                                                                            type IPendingPromise<T> = {
                                                                                                                            readonly state: 'pending';
                                                                                                                            readonly value: T | undefined;
                                                                                                                            };

                                                                                                                              type IPromiseBasedObservable

                                                                                                                              type IPromiseBasedObservable<T> = IBasePromiseBasedObservable<T> &
                                                                                                                              (IPendingPromise<T> | IFulfilledPromise<T> | IRejectedPromise);

                                                                                                                                type IRejectedPromise

                                                                                                                                type IRejectedPromise = {
                                                                                                                                readonly state: 'rejected';
                                                                                                                                readonly value: unknown;
                                                                                                                                };

                                                                                                                                  type ITransformer

                                                                                                                                  type ITransformer<A, B> = (object: A) => B;

                                                                                                                                    type ITransformerCleanup

                                                                                                                                    type ITransformerCleanup<A, B> = (
                                                                                                                                    resultObject: B | undefined,
                                                                                                                                    sourceObject?: A
                                                                                                                                    ) => void;

                                                                                                                                      type ITransformerParams

                                                                                                                                      type ITransformerParams<A, B> = {
                                                                                                                                      onCleanup?: ITransformerCleanup<A, B>;
                                                                                                                                      debugNameGenerator?: (sourceObject?: A) => string;
                                                                                                                                      keepAlive?: boolean;
                                                                                                                                      } & Omit<IComputedValueOptions<B>, 'name'>;

                                                                                                                                        type PromiseState

                                                                                                                                        type PromiseState = 'pending' | 'fulfilled' | 'rejected';

                                                                                                                                          Namespaces

                                                                                                                                          namespace fromPromise

                                                                                                                                          namespace fromPromise {}

                                                                                                                                            variable resolve

                                                                                                                                            const resolve: {
                                                                                                                                            <T>(value: T): IFulfilledPromise<T> & IBasePromiseBasedObservable<T>;
                                                                                                                                            <T>(value?: T): IFulfilledPromise<T> & IBasePromiseBasedObservable<T>;
                                                                                                                                            };

                                                                                                                                              function reject

                                                                                                                                              reject: <T>(reason: any) => IRejectedPromise & IBasePromiseBasedObservable<T>;

                                                                                                                                                Package Files (17)

                                                                                                                                                Dependencies (0)

                                                                                                                                                No dependencies.

                                                                                                                                                Dev Dependencies (17)

                                                                                                                                                Peer Dependencies (1)

                                                                                                                                                Badge

                                                                                                                                                To add a badge like this onejsDocs.io badgeto your package's README, use the codes available below.

                                                                                                                                                You may also use Shields.io to create a custom badge linking to https://www.jsdocs.io/package/mobx-utils.

                                                                                                                                                • Markdown
                                                                                                                                                  [![jsDocs.io](https://img.shields.io/badge/jsDocs.io-reference-blue)](https://www.jsdocs.io/package/mobx-utils)
                                                                                                                                                • HTML
                                                                                                                                                  <a href="https://www.jsdocs.io/package/mobx-utils"><img src="https://img.shields.io/badge/jsDocs.io-reference-blue" alt="jsDocs.io"></a>