npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mobx-observable-promise

v0.5.34

Published

Observable promise implementation for mobx stores

Downloads

318

Readme

STILL IN DEVELOPMENT

MobX Observable Promise

Promise implementation for mobx stores.

An observable promise is a simple promise with observable fields. You can track promise status using these fields (is executing?, completed?, error?).

Main target here is to minimize recurring code as much as possible. Api calls and native calls in RN cover most of the app we create, and we need to track status for each promise, show spinners, display results, catch errors and report them, or implement analytics method for each one of them.

By using this library, this becomes much easier.

Installation

npm install mobx-observable-promise --save
yarn add mobx-observable-promise

Usage

import React, {Component} from 'react';
import {observable} from "mobx";
import {ObservablePromise} from 'mobx-observable-promise';

@observer
export class App extends Component {
    @observable myApiRequest = new ObservablePromise(() => fetch(baseUri + '/endpoint'));
}
@observer
export class App extends Component {
    @observable productsCall = new ObservablePromise(() => fetch(baseUri + '/products'))

    componentDidMount() {
        this.productsCall.execute().catch()
    }
    
    render() {
        return (
            <div>
                {this.productsCall.getResult([]).map(product =>
                    <p key={product.id}>
                        {product.name}
                    </p>
                )}
                <Loader shown={this.productsCall.isExecuting} />
                <ErrorHandler calls={[this.productsCall]} />
            </div>
        )
    }

}
export class App extends Component {
    state = {
        isExecuting: false,
        isError: false,
        error: null,
        products: []
    }

    componentDidMount() {
        this.callProducts();
    }

    callProducts() {
        this.setState({isExecuting: true});
        return fetch(baseUri + '/products').then(result => {
            this.setState({
                products: result,
                isError: false,
                error: null
            })
        }).catch(e => {
            this.setState({
                isError: true,
                error: e
            })
        }).finally(() => {
            this.setState({isExecuting: false});
        })
    }

    
    render() {
        return (
            <div>
                {this.state.products.map(product =>
                    <p key={product.id}>
                        {product.name}
                    </p>
                )}
                <Loader shown={this.state.isExecuting} />
                <ErrorHandler isError={this.state.isError} 
                              error={this.state.error}
                              retry={this.callProducts}
                              name={'product-call'} />
            </div>
        )
    }

}

API

ObservablePromise

This is the base class for all promise types in this lib.

Constructor

new ObservablePromise(action, parser?, name?);

| Argument | Type | Description | ------------ | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | action | Async Function | An async action which returns a promise. This action will be run when you call execute method
| parser | (result) => any | An optional selector, which will parse action result. Can be used to implement a common error handler to all promises.
| name | string | An optional name parameter to define this observable promise, which may be useful in error reporting

Observable Fields

The following fields are marked as observable and you can use them in your observer components

| Property | Type | Description | ----------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | result | any | Resolved result object of the underlying promise | error | any | Error object, in case the promise is rejected
| isExecuting | boolean | Returns true while the promise is getting executed
| isError | boolean | Returns true if the last execution of promise was rejected, check error field for the resulted error object
| wasExecuted | boolean | Returns true if the promise is executed at least once

Computed Fields

The following fields are computed readonly properties. You can use them in your observer components but you cannot modify them directly.

| Property | Type | Description | ----------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | isExecutingFirstTime | boolean | Returns true while the promise is getting executed for the first time
| wasSuccessful | boolean | Returns true if the last execution of promise was resolved successfully, check result field for the resulted object

Other Fields

The following fields are computed readonly properties. You can use them in your observer components but you cannot modify them directly.

| Property | Type | Description | ----------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | promise | Promise | Returns the underlying promise which the action is executing / was executed lastly
| args | any | Returns the arguments which the execute was called lastly

Methods

execute(...callArgs)

Executes the actual promise which was given in constructor as action parameter. The arguments are passed directly to the action.

Example
@observable myApiRequest = new ObservablePromise((keyword) => fetch(baseUri + '/search?q=' + keyword));

myApiRequest.execute('some-keyword');

getResult(default)

If the promise was executed successfully, returns the result field, else returns default parameter of this function

Example
const list = promise.getResult([]);
// which is same as
let list;
if (promise.wasSuccessful)
    list = promise.result;
else
    list = [];

getResult(selector, default)

If the promise was executed successfully, returns the result field using the selector function, else returns default parameter of this function

Example
const list = promise.getResult(result => result.data, []);
// which is same as
let list;
if (promise.wasSuccessful)
    list = promise.result.data;
else
    list = [];

reload()

Re-executes the promise with last called arguments

reset()

Resets promise as it was never executed.

then(onResolved)

Calls and returns the then method of promise with onResolved parameter

Example
myApiRequest.execute('some-keyword').then(console.log)
// which is same as
myApiRequest.execute('some-keyword');
myApiRequest.promise.then(console.log);

catch(onRejected)

Calls and returns the catch method of promise with onRejected parameter

Example
myApiRequest.execute('some-keyword').catch(console.warn)
// which is same as
myApiRequest.execute('some-keyword');
myApiRequest.promise.catch(console.warn);

resolve(result)

This method can be used to directly set result without actually executing the promise

reject(result)

This method can be used to directly set error without actually executing the promise

chain(promise)

Chain the results with the specified promise. After executing this promise, any result will be passed to the specified promise. Note that chain methods use registerHook under the hood so you can call the returned function to unchain the promise.

const unchain = promise.chain(anotherPromise);
// later if you need
unchain();

chainResolve(promise)

Chain the result with the specified promise. After executing this promise, only successful result will be passed to the specified promise.

chainReject(promise)

Chain the error with the specified promise. After executing this promise, only error will be passed to the specified promise.

chainReload(promise)

Chain the specified promise to reload after a successful resolve.

registerHook(promise => {})

You can register a function which will be called after every promise execution. You should check if promise was executed successfully or rejected with an error.

You can create a generic error reporter here, or chain promises after one another.

registerHookOnce(promise => {})

You can register a function which will be called once after an execution.

unregisterHook(hook)

Unregisters the hook given in registerHook

queued()

This can be used in an edge case where you need to call multiple executions one after another. The result/error will always contain the latest executed promise output. See Limitations section for more detail.

Example
//This is how you can chain executions without using 'then'
myApiRequest.queued().execute('some-keyword').execute('another-keyword');
//which is same as
myApiRequest.execute('some-keyword').then(() => myApiRequest.execute('another-keyword'));

Advices and Notes

  • Use isExecuting to

Limitations

  • By design, an observable promise can only execute one promise at a time. All executions will be discarded while a promise is already executing. If possible, either chain calls with then or create multiple observable promise objects and execute them. However in case you need to call a promise multiple times without possibility to chain with then, you can use queued() method once to enable chained execution. Which means all execute calls will be chained instead of getting discarded.
Example
// Anywhere before execute()
myApiRequest.queued();
// Later whenever you need to call it, just execute it
myApiRequest.execute().then(console.log)

Test

npm run test