mobx-utils
Advanced tools
Comparing version 2.0.2 to 3.0.0
@@ -0,1 +1,49 @@ | ||
# 3.0.0 | ||
### Revamped `fromPromise`: | ||
* It is now possible to directly pass a `(resolve, reject) => {}` function to `fromPromise`, instead of a promise object | ||
* **BREAKING** `fromPromise` no longer creates a wrapping object, but rather extends the given promise, #45 | ||
* **BREAKING** Fixed #54, the resolved value of a promise is no longer deeply converted to an observable | ||
* **BREAKING** Dropped `fromPromise().reason` | ||
* **BREAKING** Improved typings of `fromPromise`. For example, the `value` property is now only available if `.state === "resolved"` (#41) | ||
* **BREAKING** Dropped optional `initialvalue` param from `fromPromise`. use `fromPromise.fullfilled(value)` instead to create a promise in some ready state | ||
* Introduced `fromPromise.reject(reason)` and `fromPromise.resolve(value?)` to create a promise based observable in a certain state, see #39 | ||
* Fixed #56, observable promises attributes `state` and `value` are now explicit observables | ||
### Introduced `asyncAction` | ||
See the [docs](https://github.com/mobxjs/mobx-utils#asyncaction) for details, but the gist of it: | ||
```javascript | ||
import {asyncAction} from "mobx-utils" | ||
mobx.useStrict(true) // don't allow state modifications outside actions | ||
class Store { | ||
@observable githubProjects = [] | ||
@state = "pending" // "pending" / "done" / "error" | ||
@asyncAction | ||
*fetchProjects() { // <- note the star, this a generator function! | ||
this.githubProjects = [] | ||
this.state = "pending" | ||
try { | ||
const projects = yield fetchGithubProjectsSomehow() // yield instead of await | ||
const filteredProjects = somePreprocessing(projects) | ||
// the asynchronous blocks will automatically be wrapped actions | ||
this.state = "done" | ||
this.githubProjects = filteredProjects | ||
} catch (error) { | ||
this.state = "error" | ||
} | ||
} | ||
} | ||
``` | ||
### Other | ||
* Fixed #40, `now()` now returns current date time if invoked from outside a reactive context | ||
# 2.0.2 | ||
@@ -2,0 +50,0 @@ |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var mobx_1 = require("mobx"); | ||
@@ -3,0 +4,0 @@ /** |
@@ -8,2 +8,3 @@ "use strict"; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var mobx_1 = require("mobx"); | ||
@@ -71,16 +72,16 @@ var utils_1 = require("./utils"); | ||
}; | ||
__decorate([ | ||
mobx_1.computed | ||
], ViewModel.prototype, "isDirty", null); | ||
__decorate([ | ||
mobx_1.action.bound | ||
], ViewModel.prototype, "submit", null); | ||
__decorate([ | ||
mobx_1.action.bound | ||
], ViewModel.prototype, "reset", null); | ||
__decorate([ | ||
mobx_1.action.bound | ||
], ViewModel.prototype, "resetProperty", null); | ||
return ViewModel; | ||
}()); | ||
__decorate([ | ||
mobx_1.computed | ||
], ViewModel.prototype, "isDirty", null); | ||
__decorate([ | ||
mobx_1.action.bound | ||
], ViewModel.prototype, "submit", null); | ||
__decorate([ | ||
mobx_1.action.bound | ||
], ViewModel.prototype, "reset", null); | ||
__decorate([ | ||
mobx_1.action.bound | ||
], ViewModel.prototype, "resetProperty", null); | ||
/** | ||
@@ -87,0 +88,0 @@ * `createViewModel` takes an object with observable properties (model) |
@@ -5,7 +5,4 @@ export declare type PromiseState = "pending" | "fulfilled" | "rejected"; | ||
export declare const REJECTED = "rejected"; | ||
export interface IPromiseBasedObservable<T> { | ||
value: T; | ||
state: PromiseState; | ||
reason: any; | ||
promise: PromiseLike<T>; | ||
export declare type IBasePromiseBasedObservable<T> = { | ||
isPromiseBasedObservable: true; | ||
case<U>(handlers: { | ||
@@ -16,3 +13,16 @@ pending?: () => U; | ||
}): U; | ||
} | ||
} & PromiseLike<T>; | ||
export declare type IPendingPromise = { | ||
readonly state: "pending"; | ||
readonly reason: any; | ||
}; | ||
export declare type IFulfilledPromise<T> = { | ||
readonly state: "fulfilled"; | ||
readonly value: T; | ||
}; | ||
export declare type IRejectedPromise = { | ||
readonly state: "rejected"; | ||
readonly value: any; | ||
}; | ||
export declare type IPromiseBasedObservable<T> = IBasePromiseBasedObservable<T> & (IPendingPromise | IFulfilledPromise<T> | IRejectedPromise); | ||
/** | ||
@@ -27,3 +37,15 @@ * `fromPromise` takes a Promise and returns an object with 3 observable properties that track | ||
* | ||
* | ||
* Note that the status strings are available as constants: | ||
* `mobxUtils.PENDING`, `mobxUtils.REJECTED`, `mobxUtil.FULFILLED` | ||
* | ||
* Observable promises can be created immediatly in a certain state using | ||
* `fromPromise.reject(reason)` or `fromPromise.resolve(value?)`. | ||
* The mean advantagate 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 | ||
* ```javascript | ||
* const fetchResult = fromPromise(fetch("http://someurl")) | ||
@@ -56,16 +78,17 @@ * | ||
* })) | ||
* ``` | ||
* | ||
* Note that the status strings are available as constants: | ||
* `mobxUtils.PENDING`, `mobxUtils.REJECTED`, `mobxUtil.FULFILLED` | ||
* | ||
* @param {IThenable<T>} promise The promise which will be observed | ||
* @param {T} [initialValue=undefined] Optional predefined initial value | ||
* @returns {IPromiseBasedObservable<T>} | ||
*/ | ||
export declare function fromPromise<T>(promise: PromiseLike<T>, initialValue?: T): IPromiseBasedObservable<T>; | ||
export declare const fromPromise: { | ||
<T>(promise: PromiseLike<T>): IPromiseBasedObservable<T>; | ||
reject<T>(reason: any): IRejectedPromise & IBasePromiseBasedObservable<T>; | ||
resolve<T>(value?: T): IFulfilledPromise<T> & IBasePromiseBasedObservable<T>; | ||
}; | ||
/** | ||
* Returns true if the provided value is a promise-based observable. | ||
* @param value any | ||
* @returns {boolean} | ||
*/ | ||
* Returns true if the provided value is a promise-based observable. | ||
* @param value any | ||
* @returns {boolean} | ||
*/ | ||
export declare function isPromiseBasedObservable(value: any): value is IPromiseBasedObservable<any>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var mobx_1 = require("mobx"); | ||
@@ -7,50 +8,43 @@ var utils_1 = require("./utils"); | ||
exports.REJECTED = "rejected"; | ||
var PromiseBasedObservable = (function () { | ||
function PromiseBasedObservable(promise, initialValue) { | ||
if (initialValue === void 0) { initialValue = undefined; } | ||
var _this = this; | ||
this.promise = promise; | ||
this._state = mobx_1.observable(exports.PENDING); // MWE: Hm... as any should not be needed... | ||
this._reason = mobx_1.observable.shallowBox(undefined); | ||
this._observable = mobx_1.observable.box(initialValue); | ||
promise.then(mobx_1.action("observableFromPromise-resolve", function (value) { | ||
_this._observable.set(value); | ||
_this._state.set("fulfilled"); | ||
function caseImpl(handlers) { | ||
switch (this.state) { | ||
case exports.PENDING: return handlers.pending && handlers.pending(); | ||
case exports.REJECTED: return handlers.rejected && handlers.rejected(this.value); | ||
case exports.FULFILLED: return handlers.fulfilled && handlers.fulfilled(this.value); | ||
} | ||
} | ||
function createObservablePromise(origPromise) { | ||
utils_1.invariant(arguments.length === 1, "fromPromise expects exactly one argument"); | ||
utils_1.invariant(typeof origPromise === "function" || | ||
(typeof origPromise === "object" && origPromise && typeof origPromise.then === "function"), "Please pass a promise or function to fromPromise"); | ||
if (typeof origPromise === "function") { | ||
// If it is a (reject, resolve function, wrap it) | ||
origPromise = new Promise(origPromise); | ||
} | ||
var promise = new Promise(function (resolve, reject) { | ||
origPromise.then(mobx_1.action("observableFromPromise-resolve", function (value) { | ||
promise.value = value; | ||
promise.state = exports.FULFILLED; | ||
resolve(value); | ||
}), mobx_1.action("observableFromPromise-reject", function (reason) { | ||
_this._reason.set(reason); | ||
_this._observable.set(reason); | ||
_this._state.set("rejected"); | ||
promise.value = reason; | ||
promise.state = exports.REJECTED; | ||
reject(reason); | ||
})); | ||
} | ||
Object.defineProperty(PromiseBasedObservable.prototype, "value", { | ||
get: function () { | ||
return this._observable.get(); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(PromiseBasedObservable.prototype, "state", { | ||
get: function () { | ||
return this._state.get(); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
promise.isPromiseBasedObservable = true; | ||
promise.case = caseImpl; | ||
mobx_1.extendShallowObservable(promise, { | ||
value: undefined, | ||
state: exports.PENDING | ||
}); | ||
Object.defineProperty(PromiseBasedObservable.prototype, "reason", { | ||
// TODO: remove in next major | ||
Object.defineProperty(promise, "promise", { | ||
get: function () { | ||
utils_1.deprecated("In `fromPromise`: `.reason` is deprecated, use `.value` instead"); | ||
return this._reason.get(); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
utils_1.deprecated("fromPromise().promise is deprecated. fromPromise now directly returns a promise"); | ||
return origPromise; | ||
} | ||
}); | ||
PromiseBasedObservable.prototype.case = function (handlers) { | ||
switch (this.state) { | ||
case "pending": return handlers.pending && handlers.pending(); | ||
case "rejected": return handlers.rejected && handlers.rejected(this.value); | ||
case "fulfilled": return handlers.fulfilled && handlers.fulfilled(this.value); | ||
} | ||
}; | ||
return PromiseBasedObservable; | ||
}()); | ||
return promise; | ||
} | ||
/** | ||
@@ -65,3 +59,15 @@ * `fromPromise` takes a Promise and returns an object with 3 observable properties that track | ||
* | ||
* | ||
* Note that the status strings are available as constants: | ||
* `mobxUtils.PENDING`, `mobxUtils.REJECTED`, `mobxUtil.FULFILLED` | ||
* | ||
* Observable promises can be created immediatly in a certain state using | ||
* `fromPromise.reject(reason)` or `fromPromise.resolve(value?)`. | ||
* The mean advantagate 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 | ||
* ```javascript | ||
* const fetchResult = fromPromise(fetch("http://someurl")) | ||
@@ -94,23 +100,29 @@ * | ||
* })) | ||
* ``` | ||
* | ||
* Note that the status strings are available as constants: | ||
* `mobxUtils.PENDING`, `mobxUtils.REJECTED`, `mobxUtil.FULFILLED` | ||
* | ||
* @param {IThenable<T>} promise The promise which will be observed | ||
* @param {T} [initialValue=undefined] Optional predefined initial value | ||
* @returns {IPromiseBasedObservable<T>} | ||
*/ | ||
function fromPromise(promise, initialValue) { | ||
if (initialValue === void 0) { initialValue = undefined; } | ||
return new PromiseBasedObservable(promise, initialValue); | ||
} | ||
exports.fromPromise = fromPromise; | ||
exports.fromPromise = createObservablePromise; | ||
exports.fromPromise.reject = mobx_1.action("fromPromise.reject", function (reason) { | ||
var p = exports.fromPromise(Promise.reject(reason)); | ||
p.state = exports.REJECTED; | ||
p.value = reason; | ||
return p; | ||
}); | ||
exports.fromPromise.resolve = mobx_1.action("fromPromise.resolve", function (value) { | ||
if (value === void 0) { value = undefined; } | ||
var p = exports.fromPromise(Promise.resolve(value)); | ||
p.state = exports.FULFILLED; | ||
p.value = value; | ||
return p; | ||
}); | ||
/** | ||
* Returns true if the provided value is a promise-based observable. | ||
* @param value any | ||
* @returns {boolean} | ||
*/ | ||
* Returns true if the provided value is a promise-based observable. | ||
* @param value any | ||
* @returns {boolean} | ||
*/ | ||
function isPromiseBasedObservable(value) { | ||
return value instanceof PromiseBasedObservable; | ||
return value && value.isPromiseBasedObservable === true; | ||
} | ||
exports.isPromiseBasedObservable = isPromiseBasedObservable; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var mobx_1 = require("mobx"); | ||
@@ -3,0 +4,0 @@ var utils_1 = require("./utils"); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var mobx_1 = require("mobx"); | ||
@@ -3,0 +4,0 @@ /** |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var mobx_1 = require("mobx"); | ||
@@ -3,0 +4,0 @@ /** |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var utils_1 = require("./utils"); | ||
@@ -3,0 +4,0 @@ var mobx_1 = require("mobx"); |
@@ -12,1 +12,2 @@ export * from "./from-promise"; | ||
export * from "./utils"; | ||
export * from "./async-action"; |
@@ -5,2 +5,3 @@ "use strict"; | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./from-promise")); | ||
@@ -17,1 +18,2 @@ __export(require("./lazy-observable")); | ||
__export(require("./utils")); | ||
__export(require("./async-action")); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var mobx_1 = require("mobx"); | ||
var from_resource_1 = require("./from-resource"); | ||
@@ -32,2 +34,6 @@ var tickers = ({}); | ||
if (interval === void 0) { interval = 1000; } | ||
if (!mobx_1.extras.isComputingDerivation()) { | ||
// See #40 | ||
return Date.now(); | ||
} | ||
if (!tickers[interval]) { | ||
@@ -34,0 +40,0 @@ if (typeof interval === "number") |
@@ -8,2 +8,3 @@ "use strict"; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var mobx_1 = require("mobx"); | ||
@@ -84,16 +85,16 @@ function observableSymbol() { | ||
}; | ||
__decorate([ | ||
mobx_1.observable.ref | ||
], StreamListener.prototype, "current", void 0); | ||
__decorate([ | ||
mobx_1.action | ||
], StreamListener.prototype, "next", null); | ||
__decorate([ | ||
mobx_1.action | ||
], StreamListener.prototype, "complete", null); | ||
__decorate([ | ||
mobx_1.action | ||
], StreamListener.prototype, "error", null); | ||
return StreamListener; | ||
}()); | ||
__decorate([ | ||
mobx_1.observable.ref | ||
], StreamListener.prototype, "current", void 0); | ||
__decorate([ | ||
mobx_1.action | ||
], StreamListener.prototype, "next", null); | ||
__decorate([ | ||
mobx_1.action | ||
], StreamListener.prototype, "complete", null); | ||
__decorate([ | ||
mobx_1.action | ||
], StreamListener.prototype, "error", null); | ||
/** | ||
@@ -100,0 +101,0 @@ * |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var mobx_1 = require("mobx"); | ||
@@ -3,0 +4,0 @@ /** |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.NOOP = function () { }; | ||
@@ -3,0 +4,0 @@ exports.IDENTITY = function (_) { return _; }; |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("mobx")):"function"==typeof define&&define.amd?define(["mobx"],t):"object"==typeof exports?exports.mobxUtils=t(require("mobx")):e.mobxUtils=t(e.mobx)}(this,function(e){return function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return e[n].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){"use strict";function n(e){for(var r in e)t.hasOwnProperty(r)||(t[r]=e[r])}n(r(6)),n(r(9)),n(r(3)),n(r(11)),n(r(5)),n(r(7)),n(r(8)),n(r(12)),n(r(4)),n(r(10)),n(r(2))},function(t,r){t.exports=e},function(e,t){"use strict";function r(e,t){if(void 0===t&&(t="Illegal state"),!e)throw new Error("[mobx-utils] "+t)}function n(e){o.indexOf(e)===-1&&(o.push(e),console.error("[mobx-utils] Deprecated: "+e))}t.NOOP=function(){},t.IDENTITY=function(e){return e},t.invariant=r;var o=[];t.deprecated=n},function(e,t,r){"use strict";function n(e,t,r){void 0===t&&(t=i.NOOP),void 0===r&&(r=void 0);var n=!1,u=!1,s=r,c=function(){n&&(n=!1,t())},a=new o.Atom("ResourceBasedObservable",function(){i.invariant(!n&&!u),n=!0,e(function(e){o.extras.allowStateChanges(!0,function(){s=e,a.reportChanged()})})},c);return{current:function(){i.invariant(!u,"subscribingObservable has already been disposed");var e=a.reportObserved();return e||n||console.warn("Called `get` of an subscribingObservable outside a reaction. Current value will be returned but no new subscription has started"),s},dispose:function(){u=!0,c()},isAlive:function(){return n}}}var o=r(1),i=r(2);t.fromResource=n},function(e,t,r){"use strict";function n(e,t,r,n){if(void 0===r&&(r=0),void 0===n&&(n=0),!o.isObservableArray(e))throw new Error("Expected observable array as first argument");o.isAction(t)||(t=o.action("chunkProcessor",t));var i=function(){for(var r=function(){var r=0===n?e.length:Math.min(e.length,n),i=e.slice(0,r);o.runInAction(function(){return e.splice(0,r)}),t(i)};e.length>0;)r()};return r>0?o.autorunAsync(i,r):o.autorun(i)}var o=r(1);t.chunkProcessor=n},function(e,t,r){"use strict";function n(e){return new c(e)}var o=this&&this.__decorate||function(e,t,r,n){var o,i=arguments.length,u=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)u=Reflect.decorate(e,t,r,n);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(u=(i<3?o(u):i>3?o(t,r,u):o(t,r))||u);return i>3&&u&&Object.defineProperty(t,r,u),u},i=r(1),u=r(2),s=["model","reset","submit","isDirty","isPropertyDirty"],c=function(){function e(e){var t=this;this.model=e,this.localValues=i.observable.map({}),this.isPropertyDirty=function(e){return t.localValues.has(e)},u.invariant(i.isObservableObject(e),"createViewModel expects an observable object"),Object.keys(e).forEach(function(e){u.invariant(s.indexOf(e)===-1,"The propertyname "+e+" is reserved and cannot be used with viewModels"),Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){return t.isPropertyDirty(e)?t.localValues.get(e):t.model[e]},set:i.action(function(r){(t.isPropertyDirty(e)||r!==t.model[e])&&t.localValues.set(e,r)})})})}return Object.defineProperty(e.prototype,"isDirty",{get:function(){return this.localValues.size>0},enumerable:!0,configurable:!0}),e.prototype.submit=function(){var e=this;this.localValues.keys().forEach(function(t){var r=e.localValues.get(t),n=e.model[t];i.isObservableArray(n)?n.replace(r):i.isObservableMap(n)?(n.clear(),n.merge(r)):e.model[t]=r}),this.localValues.clear()},e.prototype.reset=function(){this.localValues.clear()},e.prototype.resetProperty=function(e){this.localValues.delete(e)},e}();o([i.computed],c.prototype,"isDirty",null),o([i.action.bound],c.prototype,"submit",null),o([i.action.bound],c.prototype,"reset",null),o([i.action.bound],c.prototype,"resetProperty",null),t.createViewModel=n},function(e,t,r){"use strict";function n(e,t){return void 0===t&&(t=void 0),new s(e,t)}function o(e){return e instanceof s}var i=r(1),u=r(2);t.PENDING="pending",t.FULFILLED="fulfilled",t.REJECTED="rejected";var s=function(){function e(e,r){void 0===r&&(r=void 0);var n=this;this.promise=e,this._state=i.observable(t.PENDING),this._reason=i.observable.shallowBox(void 0),this._observable=i.observable.box(r),e.then(i.action("observableFromPromise-resolve",function(e){n._observable.set(e),n._state.set("fulfilled")}),i.action("observableFromPromise-reject",function(e){n._reason.set(e),n._observable.set(e),n._state.set("rejected")}))}return Object.defineProperty(e.prototype,"value",{get:function(){return this._observable.get()},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"state",{get:function(){return this._state.get()},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"reason",{get:function(){return u.deprecated("In `fromPromise`: `.reason` is deprecated, use `.value` instead"),this._reason.get()},enumerable:!0,configurable:!0}),e.prototype.case=function(e){switch(this.state){case"pending":return e.pending&&e.pending();case"rejected":return e.rejected&&e.rejected(this.value);case"fulfilled":return e.fulfilled&&e.fulfilled(this.value)}},e}();t.fromPromise=n,t.isPromiseBasedObservable=o},function(e,t,r){"use strict";function n(e,t,r,n){void 0===r&&(r=1e4),void 0===n&&(n=function(){});var i=!1,u=setTimeout(function(){i||(s(),n())},r),s=o.when(e,function(){i=!0,clearTimeout(u),t()});return function(){clearTimeout(u),s()}}var o=r(1);t.whenWithTimeout=n},function(e,t,r){"use strict";function n(e,t){var r=o.extras.getAtom(e,t);if(!r)throw new Error("No computed provided, please provide an object created with `computed(() => expr)` or an object + property name");return r.observe(function(){})}var o=r(1);t.keepAlive=n},function(e,t,r){"use strict";function n(e,t,r){void 0===t&&(t=void 0),void 0===r&&(r=o.IDENTITY);var n=!1,u=i.observable.shallowBox(r(t)),s=function(){return n||(n=!0,e(function(e){i.extras.allowStateChanges(!0,function(){u.set(e)})})),u.get()},c=i.action("lazyObservable-reset",function(){return u.set(t),u.get()});return{current:s,refresh:function(){return n?(n=!1,s()):u.get()},reset:function(){return c()}}}var o=r(2),i=r(1);t.lazyObservable=n},function(e,t,r){"use strict";function n(e){return void 0===e&&(e=1e3),s[e]||("number"==typeof e?s[e]=o(e):s[e]=i()),s[e].current()}function o(e){var t;return u.fromResource(function(r){t=setInterval(function(){return r(Date.now())},e)},function(){clearInterval(t)},Date.now())}function i(){var e=u.fromResource(function(t){function r(){window.requestAnimationFrame(function(){t(Date.now()),e.isAlive()&&r()})}r()},function(){},Date.now());return e}var u=r(3),s={};t.now=n},function(e,t,r){"use strict";function n(){return"function"==typeof Symbol&&Symbol.observable||"@@observable"}function o(){return this}function i(e){var t=c.computed(e);return r={subscribe:function(e){return{unsubscribe:t.observe("function"==typeof e?function(t){var r=t.newValue;return e(r)}:function(t){var r=t.newValue;return e.next(r)})}}},r[n()]=o,r;var r}function u(e,t){return void 0===t&&(t=void 0),new a(e,t)}var s=this&&this.__decorate||function(e,t,r,n){var o,i=arguments.length,u=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)u=Reflect.decorate(e,t,r,n);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(u=(i<3?o(u):i>3?o(t,r,u):o(t,r))||u);return i>3&&u&&Object.defineProperty(t,r,u),u},c=r(1);t.toStream=i;var a=function(){function e(e,t){var r=this;this.current=void 0,c.runInAction(function(){r.current=t,r.subscription=e.subscribe(r)})}return e.prototype.dispose=function(){this.subscription&&this.subscription.unsubscribe()},e.prototype.next=function(e){this.current=e},e.prototype.complete=function(){this.dispose()},e.prototype.error=function(e){this.current=e,this.dispose()},e}();s([c.observable.ref],a.prototype,"current",void 0),s([c.action],a.prototype,"next",null),s([c.action],a.prototype,"complete",null),s([c.action],a.prototype,"error",null),t.fromStream=u},function(e,t,r){"use strict";function n(e,t,r){if(void 0===r&&(r=0),!o.isObservableArray(e))throw new Error("Expected observable array as first argument");o.isAction(t)||(t=o.action("queueProcessor",t));var n=function(){var r=e.slice(0);o.runInAction(function(){return e.splice(0)}),r.forEach(t)};return r>0?o.autorunAsync(n,r):o.autorun(n)}var o=r(1);t.queueProcessor=n}])}); | ||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("mobx")):"function"==typeof define&&define.amd?define(["mobx"],t):"object"==typeof exports?exports.mobxUtils=t(require("mobx")):e.mobxUtils=t(e.mobx)}(this,function(e){return function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return e[n].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){"use strict";function n(e){for(var r in e)t.hasOwnProperty(r)||(t[r]=e[r])}Object.defineProperty(t,"__esModule",{value:!0}),n(r(7)),n(r(10)),n(r(3)),n(r(12)),n(r(6)),n(r(8)),n(r(9)),n(r(13)),n(r(5)),n(r(11)),n(r(2)),n(r(4))},function(t,r){t.exports=e},function(e,t){"use strict";function r(e,t){if(void 0===t&&(t="Illegal state"),!e)throw new Error("[mobx-utils] "+t)}function n(e){o.indexOf(e)===-1&&(o.push(e),console.error("[mobx-utils] Deprecated: "+e))}Object.defineProperty(t,"__esModule",{value:!0}),t.NOOP=function(){},t.IDENTITY=function(e){return e},t.invariant=r;var o=[];t.deprecated=n},function(e,t,r){"use strict";function n(e,t,r){void 0===t&&(t=i.NOOP),void 0===r&&(r=void 0);var n=!1,u=!1,c=r,s=function(){n&&(n=!1,t())},a=new o.Atom("ResourceBasedObservable",function(){i.invariant(!n&&!u),n=!0,e(function(e){o.extras.allowStateChanges(!0,function(){c=e,a.reportChanged()})})},s);return{current:function(){i.invariant(!u,"subscribingObservable has already been disposed");var e=a.reportObserved();return e||n||console.warn("Called `get` of an subscribingObservable outside a reaction. Current value will be returned but no new subscription has started"),c},dispose:function(){u=!0,s()},isAlive:function(){return n}}}Object.defineProperty(t,"__esModule",{value:!0});var o=r(1),i=r(2);t.fromResource=n},function(e,t,r){"use strict";function n(e,t){if("string"==typeof arguments[1]){var r=arguments[1],u=arguments[2];return u&&u.value?Object.assign({},u,{value:o(r,u.value)}):Object.assign({},u,{set:function(e){Object.defineProperty(this,r,i({},u,{value:n(r,e)}))}})}var s="string"==typeof e?t:e,a="string"==typeof e?e:s.name||"<unnamed async action>";return c.invariant("function"==typeof s,"asyncAction expects function as first arg, got: "+s),o(a,s)}function o(e,t){return function(){var r=this,n=arguments;return new Promise(function(o,i){function a(t){var r;try{r=u.action(e+" - runid: "+v+" - yield "+p++,d.next).call(d,t)}catch(e){return i(e)}return f(r),null}function l(t){var r;try{r=u.action(e+" - runid: "+v+" - yield "+p++,d.throw).call(d,t)}catch(e){return i(e)}f(r)}function f(e){return e.done?o(e.value):(c.invariant(e.value&&"function"==typeof e.value.then,"Only promises can be yielded to asyncAction, got: "+e),e.value.then(a,l))}var v=++s,p=0,d=u.action(e+" - runid: "+v+" - init",t).apply(r,n);a(void 0)})}}var i=this&&this.__assign||Object.assign||function(e){for(var t,r=1,n=arguments.length;r<n;r++){t=arguments[r];for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o])}return e};Object.defineProperty(t,"__esModule",{value:!0});var u=r(1),c=r(2);t.asyncAction=n;var s=0;t.createAsyncActionGenerator=o},function(e,t,r){"use strict";function n(e,t,r,n){if(void 0===r&&(r=0),void 0===n&&(n=0),!o.isObservableArray(e))throw new Error("Expected observable array as first argument");o.isAction(t)||(t=o.action("chunkProcessor",t));var i=function(){for(var r=function(){var r=0===n?e.length:Math.min(e.length,n),i=e.slice(0,r);o.runInAction(function(){return e.splice(0,r)}),t(i)};e.length>0;)r()};return r>0?o.autorunAsync(i,r):o.autorun(i)}Object.defineProperty(t,"__esModule",{value:!0});var o=r(1);t.chunkProcessor=n},function(e,t,r){"use strict";function n(e){return new s(e)}var o=this&&this.__decorate||function(e,t,r,n){var o,i=arguments.length,u=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)u=Reflect.decorate(e,t,r,n);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(u=(i<3?o(u):i>3?o(t,r,u):o(t,r))||u);return i>3&&u&&Object.defineProperty(t,r,u),u};Object.defineProperty(t,"__esModule",{value:!0});var i=r(1),u=r(2),c=["model","reset","submit","isDirty","isPropertyDirty"],s=function(){function e(e){var t=this;this.model=e,this.localValues=i.observable.map({}),this.isPropertyDirty=function(e){return t.localValues.has(e)},u.invariant(i.isObservableObject(e),"createViewModel expects an observable object"),Object.keys(e).forEach(function(e){u.invariant(c.indexOf(e)===-1,"The propertyname "+e+" is reserved and cannot be used with viewModels"),Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){return t.isPropertyDirty(e)?t.localValues.get(e):t.model[e]},set:i.action(function(r){(t.isPropertyDirty(e)||r!==t.model[e])&&t.localValues.set(e,r)})})})}return Object.defineProperty(e.prototype,"isDirty",{get:function(){return this.localValues.size>0},enumerable:!0,configurable:!0}),e.prototype.submit=function(){var e=this;this.localValues.keys().forEach(function(t){var r=e.localValues.get(t),n=e.model[t];i.isObservableArray(n)?n.replace(r):i.isObservableMap(n)?(n.clear(),n.merge(r)):e.model[t]=r}),this.localValues.clear()},e.prototype.reset=function(){this.localValues.clear()},e.prototype.resetProperty=function(e){this.localValues.delete(e)},o([i.computed],e.prototype,"isDirty",null),o([i.action.bound],e.prototype,"submit",null),o([i.action.bound],e.prototype,"reset",null),o([i.action.bound],e.prototype,"resetProperty",null),e}();t.createViewModel=n},function(e,t,r){"use strict";function n(e){switch(this.state){case t.PENDING:return e.pending&&e.pending();case t.REJECTED:return e.rejected&&e.rejected(this.value);case t.FULFILLED:return e.fulfilled&&e.fulfilled(this.value)}}function o(e){c.invariant(1===arguments.length,"fromPromise expects exactly one argument"),c.invariant("function"==typeof e||"object"==typeof e&&e&&"function"==typeof e.then,"Please pass a promise or function to fromPromise"),"function"==typeof e&&(e=new Promise(e));var r=new Promise(function(n,o){e.then(u.action("observableFromPromise-resolve",function(e){r.value=e,r.state=t.FULFILLED,n(e)}),u.action("observableFromPromise-reject",function(e){r.value=e,r.state=t.REJECTED,o(e)}))});return r.isPromiseBasedObservable=!0,r.case=n,u.extendShallowObservable(r,{value:void 0,state:t.PENDING}),Object.defineProperty(r,"promise",{get:function(){return c.deprecated("fromPromise().promise is deprecated. fromPromise now directly returns a promise"),e}}),r}function i(e){return e&&e.isPromiseBasedObservable===!0}Object.defineProperty(t,"__esModule",{value:!0});var u=r(1),c=r(2);t.PENDING="pending",t.FULFILLED="fulfilled",t.REJECTED="rejected",t.fromPromise=o,t.fromPromise.reject=u.action("fromPromise.reject",function(e){var r=t.fromPromise(Promise.reject(e));return r.state=t.REJECTED,r.value=e,r}),t.fromPromise.resolve=u.action("fromPromise.resolve",function(e){void 0===e&&(e=void 0);var r=t.fromPromise(Promise.resolve(e));return r.state=t.FULFILLED,r.value=e,r}),t.isPromiseBasedObservable=i},function(e,t,r){"use strict";function n(e,t,r,n){void 0===r&&(r=1e4),void 0===n&&(n=function(){});var i=!1,u=setTimeout(function(){i||(c(),n())},r),c=o.when(e,function(){i=!0,clearTimeout(u),t()});return function(){clearTimeout(u),c()}}Object.defineProperty(t,"__esModule",{value:!0});var o=r(1);t.whenWithTimeout=n},function(e,t,r){"use strict";function n(e,t){var r=o.extras.getAtom(e,t);if(!r)throw new Error("No computed provided, please provide an object created with `computed(() => expr)` or an object + property name");return r.observe(function(){})}Object.defineProperty(t,"__esModule",{value:!0});var o=r(1);t.keepAlive=n},function(e,t,r){"use strict";function n(e,t,r){void 0===t&&(t=void 0),void 0===r&&(r=o.IDENTITY);var n=!1,u=i.observable.shallowBox(r(t)),c=function(){return n||(n=!0,e(function(e){i.extras.allowStateChanges(!0,function(){u.set(e)})})),u.get()},s=i.action("lazyObservable-reset",function(){return u.set(t),u.get()});return{current:c,refresh:function(){return n?(n=!1,c()):u.get()},reset:function(){return s()}}}Object.defineProperty(t,"__esModule",{value:!0});var o=r(2),i=r(1);t.lazyObservable=n},function(e,t,r){"use strict";function n(e){return void 0===e&&(e=1e3),u.extras.isComputingDerivation()?(s[e]||("number"==typeof e?s[e]=o(e):s[e]=i()),s[e].current()):Date.now()}function o(e){var t;return c.fromResource(function(r){t=setInterval(function(){return r(Date.now())},e)},function(){clearInterval(t)},Date.now())}function i(){var e=c.fromResource(function(t){function r(){window.requestAnimationFrame(function(){t(Date.now()),e.isAlive()&&r()})}r()},function(){},Date.now());return e}Object.defineProperty(t,"__esModule",{value:!0});var u=r(1),c=r(3),s={};t.now=n},function(e,t,r){"use strict";function n(){return"function"==typeof Symbol&&Symbol.observable||"@@observable"}function o(){return this}function i(e){var t=s.computed(e);return r={subscribe:function(e){return{unsubscribe:t.observe("function"==typeof e?function(t){var r=t.newValue;return e(r)}:function(t){var r=t.newValue;return e.next(r)})}}},r[n()]=o,r;var r}function u(e,t){return void 0===t&&(t=void 0),new a(e,t)}var c=this&&this.__decorate||function(e,t,r,n){var o,i=arguments.length,u=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)u=Reflect.decorate(e,t,r,n);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(u=(i<3?o(u):i>3?o(t,r,u):o(t,r))||u);return i>3&&u&&Object.defineProperty(t,r,u),u};Object.defineProperty(t,"__esModule",{value:!0});var s=r(1);t.toStream=i;var a=function(){function e(e,t){var r=this;this.current=void 0,s.runInAction(function(){r.current=t,r.subscription=e.subscribe(r)})}return e.prototype.dispose=function(){this.subscription&&this.subscription.unsubscribe()},e.prototype.next=function(e){this.current=e},e.prototype.complete=function(){this.dispose()},e.prototype.error=function(e){this.current=e,this.dispose()},c([s.observable.ref],e.prototype,"current",void 0),c([s.action],e.prototype,"next",null),c([s.action],e.prototype,"complete",null),c([s.action],e.prototype,"error",null),e}();t.fromStream=u},function(e,t,r){"use strict";function n(e,t,r){if(void 0===r&&(r=0),!o.isObservableArray(e))throw new Error("Expected observable array as first argument");o.isAction(t)||(t=o.action("queueProcessor",t));var n=function(){var r=e.slice(0);o.runInAction(function(){return e.splice(0)}),r.forEach(t)};return r>0?o.autorunAsync(n,r):o.autorun(n)}Object.defineProperty(t,"__esModule",{value:!0});var o=r(1);t.queueProcessor=n}])}); |
{ | ||
"name": "mobx-utils", | ||
"version": "2.0.2", | ||
"version": "3.0.0", | ||
"description": "Utility functions and common patterns for MobX", | ||
@@ -10,3 +10,3 @@ "main": "lib/mobx-utils.js", | ||
"webpack": "webpack -p", | ||
"test": "npm run build && tape test/*.js | faucet", | ||
"test": "npm run build && tsc -p test && tape test/*.js .test-ts/*.js | faucet", | ||
"lint:js": "eslint ./test", | ||
@@ -16,5 +16,4 @@ "lint:ts": "tslint ./src/*.ts", | ||
"prepublish": "npm run build && npm run build-docs", | ||
"test-travis": "npm run build && npm run lint && istanbul cover tape test/*.js", | ||
"coverage": "npm run build && istanbul cover tape test/*.js && cat ./coverage/lcov.info|coveralls", | ||
"build-docs": "npm run build && documentation readme lib/mobx-utils.js --github --section API" | ||
"coverage": "npm run build && tsc -p test && istanbul cover tape test/*.js .test-ts/*.js && cat ./coverage/lcov.info|coveralls", | ||
"build-docs": "npm run build && documentation readme lib/mobx-utils.js --section API" | ||
}, | ||
@@ -35,2 +34,3 @@ "repository": { | ||
"devDependencies": { | ||
"@types/tape": "^4.2.30", | ||
"babel-eslint": "^7.1.0", | ||
@@ -47,3 +47,3 @@ "coveralls": "^2.11.4", | ||
"tslint-eslint-rules": "^2.1.0", | ||
"typescript": "^2.1.4", | ||
"typescript": "^2.4.2", | ||
"webpack": "^1.13.1" | ||
@@ -50,0 +50,0 @@ }, |
199
README.md
@@ -27,4 +27,2 @@ # MobX-utils | ||
[lib/from-promise.js:100-103](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/from-promise.js#L100-L103 "Source code on GitHub") | ||
`fromPromise` takes a Promise and returns an object with 3 observable properties that track | ||
@@ -39,42 +37,50 @@ the status of the promise. The returned object has the following observable properties: | ||
Note that the status strings are available as constants: | ||
`mobxUtils.PENDING`, `mobxUtils.REJECTED`, `mobxUtil.FULFILLED` | ||
Observable promises can be created immediatly in a certain state using | ||
`fromPromise.reject(reason)` or `fromPromise.resolve(value?)`. | ||
The mean advantagate 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))` | ||
**Parameters** | ||
- `promise` **IThenable<T>** The promise which will be observed | ||
- `initialValue` **T?** Optional predefined initial value (optional, default `undefined`) | ||
**Examples** | ||
```javascript | ||
const fetchResult = fromPromise(fetch("http://someurl")) | ||
````javascript | ||
```javascript | ||
const fetchResult = fromPromise(fetch("http://someurl")) | ||
// combine with when.. | ||
when( | ||
() => fetchResult.state !== "pending" | ||
() => { | ||
console.log("Got ", fetchResult.value) | ||
} | ||
) | ||
// 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 <div>Loading...</div> | ||
case "rejected": return <div>Ooops... {fetchResult.value}</div> | ||
case "fulfilled": return <div>Gotcha: {fetchResult.value}</div> | ||
} | ||
}) | ||
// or a mobx-react component.. | ||
const myComponent = observer(({ fetchResult }) => { | ||
switch(fetchResult.state) { | ||
case "pending": return <div>Loading...</div> | ||
case "rejected": return <div>Ooops... {fetchResult.value}</div> | ||
case "fulfilled": return <div>Gotcha: {fetchResult.value}</div> | ||
} | ||
}) | ||
// or using the case method instead of switch: | ||
// or using the case method instead of switch: | ||
const myComponent = observer(({ fetchResult }) => | ||
fetchResult.case({ | ||
pending: () => <div>Loading...</div> | ||
rejected: error => <div>Ooops.. {error}</div> | ||
fulfilled: value => <div>Gotcha: {value}</div> | ||
})) | ||
const myComponent = observer(({ fetchResult }) => | ||
fetchResult.case({ | ||
pending: () => <div>Loading...</div> | ||
rejected: error => <div>Ooops.. {error}</div> | ||
fulfilled: value => <div>Gotcha: {value}</div> | ||
})) | ||
``` | ||
```` | ||
Note that the status strings are available as constants: | ||
`mobxUtils.PENDING`, `mobxUtils.REJECTED`, `mobxUtil.FULFILLED` | ||
``` | ||
Returns **IPromiseBasedObservable<T>** | ||
@@ -84,4 +90,2 @@ | ||
[lib/from-promise.js:110-112](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/from-promise.js#L110-L112 "Source code on GitHub") | ||
Returns true if the provided value is a promise-based observable. | ||
@@ -97,4 +101,2 @@ | ||
[lib/lazy-observable.js:37-72](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/lazy-observable.js#L37-L72 "Source code on GitHub") | ||
`lazyObservable` creates an observable around a `fetch` method that will not be invoked | ||
@@ -135,4 +137,2 @@ until the observable is needed the first time. | ||
[lib/from-resource.js:68-104](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/from-resource.js#L68-L104 "Source code on GitHub") | ||
`fromResource` creates an observable whose current state can be inspected using `.current()`, | ||
@@ -201,4 +201,2 @@ and which can be kept in sync with some external datasource that can be subscribed to. | ||
[lib/observable-stream.js:37-57](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/observable-stream.js#L37-L57 "Source code on GitHub") | ||
Converts an expression to an observable stream (a.k.a. TC 39 Observable / RxJS observable). | ||
@@ -230,4 +228,2 @@ The provided expression is tracked by mobx as long as there are subscribers, automatically | ||
[lib/observable-stream.js:122-125](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/observable-stream.js#L122-L125 "Source code on GitHub") | ||
Converts an subscribable, observable stream (TC 39 observable / RxJS stream) | ||
@@ -258,4 +254,2 @@ into an object which stores the current value (as `current`). The subscription can be cancelled through the `dispose` method. | ||
[lib/create-view-model.js:127-129](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/create-view-model.js#L127-L129 "Source code on GitHub") | ||
`createViewModel` takes an object with observable properties (model) | ||
@@ -310,4 +304,2 @@ and wraps a viewmodel around it. The viewmodel proxies all enumerable property of the original model with the following behavior: | ||
[lib/guarded-when.js:32-51](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/guarded-when.js#L32-L51 "Source code on GitHub") | ||
Like normal `when`, except that this `when` will automatically dispose if the condition isn't met within a certain amount of time. | ||
@@ -347,7 +339,10 @@ | ||
[lib/keep-alive.js:31-36](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/keep-alive.js#L31-L36 "Source code on GitHub") | ||
MobX normally suspends any computed value that is not in use by any reaction, | ||
and lazily re-evaluates the expression if needed outside a reaction while not in use. | ||
`keepAlive` marks a computed value as always in use, meaning that it will always fresh, but never disposed automatically. | ||
**Parameters** | ||
- `computedValue` **IComputedValue<any>** created using the `computed` function | ||
- `target` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** an object that has a computed property, created by `@computed` or `extendObservable` | ||
- `property` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the property to keep alive | ||
- `_1` | ||
@@ -359,8 +354,7 @@ - `_2` | ||
```javascript | ||
const number = observable(3) | ||
const doubler = computed(() => number.get() * 2) | ||
const stop = keepAlive(doubler) | ||
// doubler will now stay in sync reactively even when there are no further observers | ||
stop() | ||
// normal behavior, doubler results will be recomputed if not observed but needed, but lazily | ||
const obj = observable({ | ||
number: 3, | ||
doubler: function() { return this.number * 2 } | ||
}) | ||
const stop = keepAlive(obj, "doubler") | ||
``` | ||
@@ -372,12 +366,5 @@ | ||
[lib/keep-alive.js:31-36](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/keep-alive.js#L31-L36 "Source code on GitHub") | ||
MobX normally suspends any computed value that is not in use by any reaction, | ||
and lazily re-evaluates the expression if needed outside a reaction while not in use. | ||
`keepAlive` marks a computed value as always in use, meaning that it will always fresh, but never disposed automatically. | ||
**Parameters** | ||
- `target` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** an object that has a computed property, created by `@computed` or `extendObservable` | ||
- `property` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the property to keep alive | ||
- `computedValue` **IComputedValue<any>** created using the `computed` function | ||
- `_1` | ||
@@ -389,7 +376,8 @@ - `_2` | ||
```javascript | ||
const obj = observable({ | ||
number: 3, | ||
doubler: function() { return this.number * 2 } | ||
}) | ||
const stop = keepAlive(obj, "doubler") | ||
const number = observable(3) | ||
const doubler = computed(() => number.get() * 2) | ||
const stop = keepAlive(doubler) | ||
// doubler will now stay in sync reactively even when there are no further observers | ||
stop() | ||
// normal behavior, doubler results will be recomputed if not observed but needed, but lazily | ||
``` | ||
@@ -401,4 +389,2 @@ | ||
[lib/queue-processor.js:22-40](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/queue-processor.js#L22-L40 "Source code on GitHub") | ||
`queueProcessor` takes an observable array, observes it and calls `processor` | ||
@@ -430,4 +416,2 @@ once for each item added to the observable array, optionally deboucing the action | ||
[lib/chunk-processor.js:27-52](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/chunk-processor.js#L27-L52 "Source code on GitHub") | ||
`chunkProcessor` takes an observable array, observes it and calls `processor` | ||
@@ -464,4 +448,2 @@ once for a chunk of items added to the observable array, optionally deboucing the action. | ||
[lib/now.js:30-39](https://github.com/mobxjs/mobx-utils/blob/2e0d881a4901917426571319d529adbc9a3b3afa/lib/now.js#L30-L39 "Source code on GitHub") | ||
Returns the current date time as epoch number. | ||
@@ -492,1 +474,74 @@ The date time is read from an observable which is updated automatically after the given interval. | ||
``` | ||
## asyncAction | ||
`asyncAction` takes a generator function and automatically wraps all parts of the process in actions. See the examples below. | ||
`asyncAction` can be used both as decorator or to wrap functions. | ||
- It is important that `asyncAction should always be used with a generator function (recognizable as`function_`or`_name\` syntax) | ||
- Each yield statement should return a Promise. The generator function will continue as soon as the promise settles, with the settled value | ||
- When the generator function finishes, you can return a normal value. The `asyncAction` wrapped function will always produce a promise delivering that value. | ||
When using the mobx devTools, an asyncAction will emit `action` events with names like: | ||
- `"fetchUsers - runid: 6 - init"` | ||
- `"fetchUsers - runid: 6 - yield 0"` | ||
- `"fetchUsers - runid: 6 - yield 1"` | ||
The `runId` represents the generator instance. In other words, if `fetchUsers` is invoked multiple times concurrently, the events with the same `runid` belong toghether. | ||
The `yield` number indicates the progress of the generator. `init` indicates spawning (it won't do anything, but you can find the original arguments of the `asyncAction` here). | ||
`yield 0` ... `yield n` indicates the code block that is now being executed. `yield 0` is before the first `yield`, `yield 1` after the first one etc. Note that yield numbers are not determined lexically but by the runtime flow. | ||
`asyncActions` requires `Promise` and `generators` to be available on the target environment. Polyfill `Promise` if needed. Both TypeScript and Babel can compile generator functions down to ES5. | ||
**Parameters** | ||
- `arg1` | ||
- `arg2` | ||
**Examples** | ||
```javascript | ||
import {asyncAction} from "mobx-utils" | ||
let users = [] | ||
const fetchUsers = asyncAction("fetchUsers", function* (url) { | ||
const start = Date.now() | ||
const data = yield window.fetch(url) | ||
users = yield data.json() | ||
return start - Date.now() | ||
}) | ||
fetchUsers("http://users.com").then(time => { | ||
console.dir("Got users", users, "in ", time, "ms") | ||
}) | ||
``` | ||
```javascript | ||
import {asyncAction} from "mobx-utils" | ||
mobx.useStrict(true) // don't allow state modifications outside actions | ||
class Store { | ||
\@observable githubProjects = [] | ||
\@state = "pending" // "pending" / "done" / "error" | ||
\@asyncAction | ||
*fetchProjects() { // <- note the star, this a generator function! | ||
this.githubProjects = [] | ||
this.state = "pending" | ||
try { | ||
const projects = yield fetchGithubProjectsSomehow() // yield instead of await | ||
const filteredProjects = somePreprocessing(projects) | ||
// the asynchronous blocks will automatically be wrapped actions | ||
this.state = "done" | ||
this.githubProjects = filteredProjects | ||
} catch (error) { | ||
this.state = "error" | ||
} | ||
} | ||
} | ||
``` | ||
Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)** |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
151132
59
2748
531
14
2