mobx-utils
Advanced tools
Comparing version 3.2.2 to 4.0.0-beta.2
@@ -37,3 +37,3 @@ # 3.2.2 | ||
mobx.useStrict(true) // don't allow state modifications outside actions | ||
mobx.configure({ enforceActions: true }) // don't allow state modifications outside actions | ||
@@ -40,0 +40,0 @@ class Store { |
@@ -22,2 +22,1 @@ export declare function asyncAction(target: Object, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor; | ||
export declare function asyncAction<A1>(name: string, generator: (a1: A1) => IterableIterator<any>): (a1: A1) => Promise<any>; | ||
export declare function createAsyncActionGenerator(name: string, generator: Function): () => Promise<{}>; |
@@ -1,11 +0,3 @@ | ||
var __assign = (this && this.__assign) || Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
import { action } from "mobx"; | ||
import { invariant } from "./utils"; | ||
import { flow } from "mobx"; | ||
import { deprecated } from "./utils"; | ||
/** | ||
@@ -30,2 +22,4 @@ * `asyncAction` takes a generator function and automatically wraps all parts of the process in actions. See the examples below. | ||
* | ||
* N.B. due to a [babel limitation](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy/issues/26), in Babel generatos cannot be combined with decorators. See also [#70](https://github.com/mobxjs/mobx-utils/issues/70) | ||
* | ||
* @example | ||
@@ -50,3 +44,3 @@ * import {asyncAction} from "mobx-utils" | ||
* | ||
* mobx.useStrict(true) // don't allow state modifications outside actions | ||
* mobx.configure({ enforceActions: true }) // don't allow state modifications outside actions | ||
* | ||
@@ -77,66 +71,4 @@ * class Store { | ||
export function asyncAction(arg1, arg2) { | ||
// decorator | ||
if (typeof arguments[1] === "string") { | ||
var name_1 = arguments[1]; | ||
var descriptor_1 = arguments[2]; | ||
if (descriptor_1 && descriptor_1.value) { | ||
return Object.assign({}, descriptor_1, { | ||
value: createAsyncActionGenerator(name_1, descriptor_1.value) | ||
}); | ||
} | ||
else { | ||
return Object.assign({}, descriptor_1, { | ||
set: function (v) { | ||
Object.defineProperty(this, name_1, __assign({}, descriptor_1, { value: asyncAction(name_1, v) })); | ||
} | ||
}); | ||
} | ||
} | ||
// direct invocation | ||
var generator = typeof arg1 === "string" ? arg2 : arg1; | ||
var name = typeof arg1 === "string" ? arg1 : generator.name || "<unnamed async action>"; | ||
invariant(typeof generator === "function", "asyncAction expects function as first arg, got: " + generator); | ||
return createAsyncActionGenerator(name, generator); | ||
deprecated("asyncAction is deprecated. use mobx.flow instead"); | ||
return flow.apply(null, arguments); | ||
} | ||
var generatorId = 0; | ||
export function createAsyncActionGenerator(name, generator) { | ||
// Implementation based on https://github.com/tj/co/blob/master/index.js | ||
return function () { | ||
var ctx = this; | ||
var args = arguments; | ||
return new Promise(function (resolve, reject) { | ||
var runId = ++generatorId; | ||
var stepId = 0; | ||
var gen = action(name + " - runid: " + runId + " - init", generator).apply(ctx, args); | ||
onFulfilled(undefined); // kick off the process | ||
function onFulfilled(res) { | ||
var ret; | ||
try { | ||
ret = action(name + " - runid: " + runId + " - yield " + stepId++, gen.next).call(gen, res); | ||
} | ||
catch (e) { | ||
return reject(e); | ||
} | ||
next(ret); | ||
return null; | ||
} | ||
function onRejected(err) { | ||
var ret; | ||
try { | ||
ret = action(name + " - runid: " + runId + " - yield " + stepId++, gen.throw).call(gen, err); | ||
} | ||
catch (e) { | ||
return reject(e); | ||
} | ||
next(ret); | ||
} | ||
function next(ret) { | ||
if (ret.done) | ||
return resolve(ret.value); | ||
// TODO: support more type of values? See https://github.com/tj/co/blob/249bbdc72da24ae44076afd716349d2089b31c4c/index.js#L100 | ||
invariant(ret.value && typeof ret.value.then === "function", "Only promises can be yielded to asyncAction, got: " + ret); | ||
return ret.value.then(onFulfilled, onRejected); | ||
} | ||
}); | ||
}; | ||
} |
@@ -1,2 +0,2 @@ | ||
import { isAction, autorun, autorunAsync, action, isObservableArray, runInAction } from "mobx"; | ||
import { isAction, autorun, action, isObservableArray, runInAction } from "mobx"; | ||
/** | ||
@@ -50,5 +50,5 @@ * `chunkProcessor` takes an observable array, observes it and calls `processor` | ||
if (debounce > 0) | ||
return autorunAsync(runner, debounce); | ||
return autorun(runner, { delay: debounce }); | ||
else | ||
return autorun(runner); | ||
} |
@@ -7,3 +7,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
}; | ||
import { action, observable, isObservableObject, isObservableArray, isObservableMap, computed } from "mobx"; | ||
import { action, observable, isObservableObject, isObservableArray, isObservableMap, computed, keys } from "mobx"; | ||
import { invariant } from "./utils"; | ||
@@ -48,3 +48,3 @@ var RESERVED_NAMES = ["model", "reset", "submit", "isDirty", "isPropertyDirty"]; | ||
var _this = this; | ||
this.localValues.keys().forEach(function (key) { | ||
keys(this.localValues).forEach(function (key) { | ||
var source = _this.localValues.get(key); | ||
@@ -51,0 +51,0 @@ var destination = _this.model[key]; |
@@ -27,3 +27,3 @@ export declare type PromiseState = "pending" | "fulfilled" | "rejected"; | ||
/** | ||
* `fromPromise` takes a Promise and returns an object with 3 observable properties that track | ||
* `fromPromise` takes a Promise and returns a new Promise wrapping the original one. The returned Promise is also extended with 2 observable properties that track | ||
* the status of the promise. The returned object has the following observable properties: | ||
@@ -37,3 +37,3 @@ * - `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. | ||
* | ||
* The returned object implements `PromiseLike<TValue>`, so you can chain additional `Promise` handlers using `then`. | ||
* 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. | ||
* | ||
@@ -40,0 +40,0 @@ * Note that the status strings are available as constants: |
@@ -1,3 +0,3 @@ | ||
import { extendShallowObservable, action } from "mobx"; | ||
import { deprecated, invariant } from "./utils"; | ||
import { action, extendObservable } from "mobx"; | ||
import { invariant } from "./utils"; | ||
export var PENDING = "pending"; | ||
@@ -26,30 +26,20 @@ export var FULFILLED = "fulfilled"; | ||
} | ||
var promise = new Promise(function (resolve, reject) { | ||
origPromise.then(action("observableFromPromise-resolve", function (value) { | ||
promise.value = value; | ||
promise.state = FULFILLED; | ||
resolve(value); | ||
}), action("observableFromPromise-reject", function (reason) { | ||
promise.value = reason; | ||
promise.state = REJECTED; | ||
reject(reason); | ||
})); | ||
}); | ||
var promise = origPromise; | ||
origPromise.then(action("observableFromPromise-resolve", function (value) { | ||
promise.value = value; | ||
promise.state = FULFILLED; | ||
}), action("observableFromPromise-reject", function (reason) { | ||
promise.value = reason; | ||
promise.state = REJECTED; | ||
})); | ||
promise.isPromiseBasedObservable = true; | ||
promise.case = caseImpl; | ||
extendShallowObservable(promise, { | ||
extendObservable(promise, { | ||
value: undefined, | ||
state: PENDING | ||
}); | ||
// TODO: remove in next major | ||
Object.defineProperty(promise, "promise", { | ||
get: function () { | ||
deprecated("fromPromise().promise is deprecated. fromPromise now directly returns a promise"); | ||
return origPromise; | ||
} | ||
}); | ||
}, {}, { deep: false }); | ||
return promise; | ||
} | ||
/** | ||
* `fromPromise` takes a Promise and returns an object with 3 observable properties that track | ||
* `fromPromise` takes a Promise and returns a new Promise wrapping the original one. The returned Promise is also extended with 2 observable properties that track | ||
* the status of the promise. The returned object has the following observable properties: | ||
@@ -63,3 +53,3 @@ * - `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. | ||
* | ||
* The returned object implements `PromiseLike<TValue>`, so you can chain additional `Promise` handlers using `then`. | ||
* 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. | ||
* | ||
@@ -66,0 +56,0 @@ * Note that the status strings are available as constants: |
@@ -1,2 +0,2 @@ | ||
import { Atom, extras } from "mobx"; | ||
import { createAtom, _allowStateChanges } from "mobx"; | ||
import { NOOP, invariant } from "./utils"; | ||
@@ -79,7 +79,7 @@ /** | ||
}; | ||
var atom = new Atom("ResourceBasedObservable", function () { | ||
var atom = createAtom("ResourceBasedObservable", function () { | ||
invariant(!isActive && !isDisposed); | ||
isActive = true; | ||
subscriber(function (newValue) { | ||
extras.allowStateChanges(true, function () { | ||
_allowStateChanges(true, function () { | ||
value = newValue; | ||
@@ -86,0 +86,0 @@ atom.reportChanged(); |
import { when } from "mobx"; | ||
import { deprecated } from "./utils"; | ||
/** | ||
@@ -34,18 +35,7 @@ * Like normal `when`, except that this `when` will automatically dispose if the condition isn't met within a certain amount of time. | ||
if (onTimeout === void 0) { onTimeout = function () { }; } | ||
var done = false; | ||
var handle = setTimeout(function () { | ||
if (!done) { | ||
disposer(); | ||
onTimeout(); | ||
} | ||
}, timeout); | ||
var disposer = when(expr, function () { | ||
done = true; | ||
clearTimeout(handle); | ||
action(); | ||
deprecated("whenWithTimeout is deprecated, use mobx.when with timeout option instead"); | ||
return when(expr, action, { | ||
timeout: timeout, | ||
onError: onTimeout | ||
}); | ||
return function () { | ||
clearTimeout(handle); | ||
disposer(); | ||
}; | ||
} |
@@ -1,2 +0,2 @@ | ||
import { extras } from "mobx"; | ||
import { getAtom } from "mobx"; | ||
/** | ||
@@ -31,3 +31,3 @@ * MobX normally suspends any computed value that is not in use by any reaction, | ||
export function keepAlive(_1, _2) { | ||
var computed = extras.getAtom(_1, _2); | ||
var computed = getAtom(_1, _2); | ||
if (!computed) | ||
@@ -34,0 +34,0 @@ throw new Error("No computed provided, please provide an object created with `computed(() => expr)` or an object + property name"); |
@@ -39,2 +39,2 @@ export interface ILazyObservable<T> { | ||
*/ | ||
export declare function lazyObservable<T>(fetch: (sink: (newValue: T) => void) => void, initialValue?: T, modifier?: (_: any) => any): ILazyObservable<T>; | ||
export declare function lazyObservable<T>(fetch: (sink: (newValue: T) => void) => void, initialValue?: T): ILazyObservable<T>; |
@@ -1,3 +0,2 @@ | ||
import { IDENTITY } from "./utils"; | ||
import { observable, extras, action } from "mobx"; | ||
import { observable, action, _allowStateChanges } from "mobx"; | ||
/** | ||
@@ -36,7 +35,6 @@ * `lazyObservable` creates an observable around a `fetch` method that will not be invoked | ||
*/ | ||
export function lazyObservable(fetch, initialValue, modifier) { | ||
export function lazyObservable(fetch, initialValue) { | ||
if (initialValue === void 0) { initialValue = undefined; } | ||
if (modifier === void 0) { modifier = IDENTITY; } | ||
var started = false; | ||
var value = observable.shallowBox(modifier(initialValue)); | ||
var value = observable.box(initialValue, { deep: false }); | ||
var currentFnc = function () { | ||
@@ -46,3 +44,3 @@ if (!started) { | ||
fetch(function (newValue) { | ||
extras.allowStateChanges(true, function () { | ||
_allowStateChanges(true, function () { | ||
value.set(newValue); | ||
@@ -49,0 +47,0 @@ }); |
@@ -14,1 +14,3 @@ export * from "./from-promise"; | ||
export * from "./when-async"; | ||
export * from "./expr"; | ||
export * from "./create-transformer"; |
@@ -14,1 +14,3 @@ export * from "./from-promise"; | ||
export * from "./when-async"; | ||
export * from "./expr"; | ||
export * from "./create-transformer"; |
@@ -1,2 +0,2 @@ | ||
import { extras } from "mobx"; | ||
import { _isComputingDerivation } from "mobx"; | ||
import { fromResource } from "./from-resource"; | ||
@@ -32,3 +32,3 @@ var tickers = {}; | ||
if (interval === void 0) { interval = 1000; } | ||
if (!extras.isComputingDerivation()) { | ||
if (!_isComputingDerivation()) { | ||
// See #40 | ||
@@ -35,0 +35,0 @@ return Date.now(); |
@@ -87,9 +87,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
__decorate([ | ||
action | ||
action.bound | ||
], StreamListener.prototype, "next", null); | ||
__decorate([ | ||
action | ||
action.bound | ||
], StreamListener.prototype, "complete", null); | ||
__decorate([ | ||
action | ||
action.bound | ||
], StreamListener.prototype, "error", null); | ||
@@ -96,0 +96,0 @@ return StreamListener; |
@@ -1,2 +0,2 @@ | ||
import { isAction, autorun, autorunAsync, action, isObservableArray, runInAction } from "mobx"; | ||
import { isAction, autorun, action, isObservableArray, runInAction } from "mobx"; | ||
/** | ||
@@ -36,5 +36,5 @@ * `queueProcessor` takes an observable array, observes it and calls `processor` | ||
if (debounce > 0) | ||
return autorunAsync(runner, debounce); | ||
return autorun(runner, { delay: debounce }); | ||
else | ||
return autorun(runner); | ||
} |
@@ -6,1 +6,2 @@ export declare type IDisposer = () => void; | ||
export declare function deprecated(msg: string): void; | ||
export declare function addHiddenProp(object: any, propName: string, value: any): void; |
@@ -15,1 +15,9 @@ export var NOOP = function () { }; | ||
} | ||
export function addHiddenProp(object, propName, value) { | ||
Object.defineProperty(object, propName, { | ||
enumerable: false, | ||
writable: true, | ||
configurable: true, | ||
value: value | ||
}); | ||
} |
import { when } from "mobx"; | ||
import { deprecated } from "./utils"; | ||
/** | ||
@@ -15,15 +16,6 @@ * Like normal `when`, except that this `when` will return a promise that resolves when the expression becomes truthy | ||
if (timeout === void 0) { timeout = 0; } | ||
return new Promise(function (resolve, reject) { | ||
var timeoutHandle; | ||
var disposer = when(fn, function () { | ||
if (timeout > 0) | ||
clearTimeout(timeoutHandle); | ||
resolve(); | ||
}); | ||
if (timeout > 0) | ||
setTimeout(function () { | ||
disposer(); | ||
reject(new Error("TIMEOUT")); | ||
}, timeout); | ||
deprecated("whenAsync is deprecated, use mobx.when without effect instead"); | ||
return when(fn, { | ||
timeout: timeout | ||
}); | ||
} |
@@ -1,2 +0,2 @@ | ||
import { Atom, action, autorun, autorunAsync, computed, extendShallowObservable, extras, isAction, isObservableArray, isObservableMap, isObservableObject, observable, runInAction, when } from 'mobx'; | ||
import { _allowStateChanges, _isComputingDerivation, action, autorun, computed, createAtom, extendObservable, flow, getAtom, isAction, isObservableArray, isObservableMap, isObservableObject, keys, observable, onBecomeUnobserved, runInAction, when } from 'mobx'; | ||
@@ -17,2 +17,10 @@ var NOOP = function () { }; | ||
} | ||
function addHiddenProp(object, propName, value) { | ||
Object.defineProperty(object, propName, { | ||
enumerable: false, | ||
writable: true, | ||
configurable: true, | ||
value: value | ||
}); | ||
} | ||
@@ -42,30 +50,20 @@ var PENDING = "pending"; | ||
} | ||
var promise = new Promise(function (resolve, reject) { | ||
origPromise.then(action("observableFromPromise-resolve", function (value) { | ||
promise.value = value; | ||
promise.state = FULFILLED; | ||
resolve(value); | ||
}), action("observableFromPromise-reject", function (reason) { | ||
promise.value = reason; | ||
promise.state = REJECTED; | ||
reject(reason); | ||
})); | ||
}); | ||
var promise = origPromise; | ||
origPromise.then(action("observableFromPromise-resolve", function (value) { | ||
promise.value = value; | ||
promise.state = FULFILLED; | ||
}), action("observableFromPromise-reject", function (reason) { | ||
promise.value = reason; | ||
promise.state = REJECTED; | ||
})); | ||
promise.isPromiseBasedObservable = true; | ||
promise.case = caseImpl; | ||
extendShallowObservable(promise, { | ||
extendObservable(promise, { | ||
value: undefined, | ||
state: PENDING | ||
}); | ||
// TODO: remove in next major | ||
Object.defineProperty(promise, "promise", { | ||
get: function () { | ||
deprecated("fromPromise().promise is deprecated. fromPromise now directly returns a promise"); | ||
return origPromise; | ||
} | ||
}); | ||
}, {}, { deep: false }); | ||
return promise; | ||
} | ||
/** | ||
* `fromPromise` takes a Promise and returns an object with 3 observable properties that track | ||
* `fromPromise` takes a Promise and returns a new Promise wrapping the original one. The returned Promise is also extended with 2 observable properties that track | ||
* the status of the promise. The returned object has the following observable properties: | ||
@@ -79,3 +77,3 @@ * - `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. | ||
* | ||
* The returned object implements `PromiseLike<TValue>`, so you can chain additional `Promise` handlers using `then`. | ||
* 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. | ||
* | ||
@@ -189,7 +187,6 @@ * Note that the status strings are available as constants: | ||
*/ | ||
function lazyObservable(fetch, initialValue, modifier) { | ||
function lazyObservable(fetch, initialValue) { | ||
if (initialValue === void 0) { initialValue = undefined; } | ||
if (modifier === void 0) { modifier = IDENTITY; } | ||
var started = false; | ||
var value = observable.shallowBox(modifier(initialValue)); | ||
var value = observable.box(initialValue, { deep: false }); | ||
var currentFnc = function () { | ||
@@ -199,3 +196,3 @@ if (!started) { | ||
fetch(function (newValue) { | ||
extras.allowStateChanges(true, function () { | ||
_allowStateChanges(true, function () { | ||
value.set(newValue); | ||
@@ -304,7 +301,7 @@ }); | ||
}; | ||
var atom = new Atom("ResourceBasedObservable", function () { | ||
var atom = createAtom("ResourceBasedObservable", function () { | ||
invariant(!isActive && !isDisposed); | ||
isActive = true; | ||
subscriber(function (newValue) { | ||
extras.allowStateChanges(true, function () { | ||
_allowStateChanges(true, function () { | ||
value = newValue; | ||
@@ -416,9 +413,9 @@ atom.reportChanged(); | ||
__decorate([ | ||
action | ||
action.bound | ||
], StreamListener.prototype, "next", null); | ||
__decorate([ | ||
action | ||
action.bound | ||
], StreamListener.prototype, "complete", null); | ||
__decorate([ | ||
action | ||
action.bound | ||
], StreamListener.prototype, "error", null); | ||
@@ -501,3 +498,3 @@ return StreamListener; | ||
var _this = this; | ||
this.localValues.keys().forEach(function (key) { | ||
keys(this.localValues).forEach(function (key) { | ||
var source = _this.localValues.get(key); | ||
@@ -618,18 +615,7 @@ var destination = _this.model[key]; | ||
if (onTimeout === void 0) { onTimeout = function () { }; } | ||
var done = false; | ||
var handle = setTimeout(function () { | ||
if (!done) { | ||
disposer(); | ||
onTimeout(); | ||
} | ||
}, timeout); | ||
var disposer = when(expr, function () { | ||
done = true; | ||
clearTimeout(handle); | ||
action$$1(); | ||
deprecated("whenWithTimeout is deprecated, use mobx.when with timeout option instead"); | ||
return when(expr, action$$1, { | ||
timeout: timeout, | ||
onError: onTimeout | ||
}); | ||
return function () { | ||
clearTimeout(handle); | ||
disposer(); | ||
}; | ||
} | ||
@@ -666,3 +652,3 @@ | ||
function keepAlive(_1, _2) { | ||
var computed$$1 = extras.getAtom(_1, _2); | ||
var computed$$1 = getAtom(_1, _2); | ||
if (!computed$$1) | ||
@@ -707,3 +693,3 @@ throw new Error("No computed provided, please provide an object created with `computed(() => expr)` or an object + property name"); | ||
if (debounce > 0) | ||
return autorunAsync(runner, debounce); | ||
return autorun(runner, { delay: debounce }); | ||
else | ||
@@ -761,3 +747,3 @@ return autorun(runner); | ||
if (debounce > 0) | ||
return autorunAsync(runner, debounce); | ||
return autorun(runner, { delay: debounce }); | ||
else | ||
@@ -796,3 +782,3 @@ return autorun(runner); | ||
if (interval === void 0) { interval = 1000; } | ||
if (!extras.isComputingDerivation()) { | ||
if (!_isComputingDerivation()) { | ||
// See #40 | ||
@@ -831,10 +817,2 @@ return Date.now(); | ||
var __assign = (undefined && undefined.__assign) || Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
/** | ||
@@ -859,2 +837,4 @@ * `asyncAction` takes a generator function and automatically wraps all parts of the process in actions. See the examples below. | ||
* | ||
* N.B. due to a [babel limitation](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy/issues/26), in Babel generatos cannot be combined with decorators. See also [#70](https://github.com/mobxjs/mobx-utils/issues/70) | ||
* | ||
* @example | ||
@@ -879,3 +859,3 @@ * import {asyncAction} from "mobx-utils" | ||
* | ||
* mobx.useStrict(true) // don't allow state modifications outside actions | ||
* mobx.configure({ enforceActions: true }) // don't allow state modifications outside actions | ||
* | ||
@@ -906,67 +886,5 @@ * class Store { | ||
function asyncAction(arg1, arg2) { | ||
// decorator | ||
if (typeof arguments[1] === "string") { | ||
var name_1 = arguments[1]; | ||
var descriptor_1 = arguments[2]; | ||
if (descriptor_1 && descriptor_1.value) { | ||
return Object.assign({}, descriptor_1, { | ||
value: createAsyncActionGenerator(name_1, descriptor_1.value) | ||
}); | ||
} | ||
else { | ||
return Object.assign({}, descriptor_1, { | ||
set: function (v) { | ||
Object.defineProperty(this, name_1, __assign({}, descriptor_1, { value: asyncAction(name_1, v) })); | ||
} | ||
}); | ||
} | ||
} | ||
// direct invocation | ||
var generator = typeof arg1 === "string" ? arg2 : arg1; | ||
var name = typeof arg1 === "string" ? arg1 : generator.name || "<unnamed async action>"; | ||
invariant(typeof generator === "function", "asyncAction expects function as first arg, got: " + generator); | ||
return createAsyncActionGenerator(name, generator); | ||
deprecated("asyncAction is deprecated. use mobx.flow instead"); | ||
return flow.apply(null, arguments); | ||
} | ||
var generatorId = 0; | ||
function createAsyncActionGenerator(name, generator) { | ||
// Implementation based on https://github.com/tj/co/blob/master/index.js | ||
return function () { | ||
var ctx = this; | ||
var args = arguments; | ||
return new Promise(function (resolve, reject) { | ||
var runId = ++generatorId; | ||
var stepId = 0; | ||
var gen = action(name + " - runid: " + runId + " - init", generator).apply(ctx, args); | ||
onFulfilled(undefined); // kick off the process | ||
function onFulfilled(res) { | ||
var ret; | ||
try { | ||
ret = action(name + " - runid: " + runId + " - yield " + stepId++, gen.next).call(gen, res); | ||
} | ||
catch (e) { | ||
return reject(e); | ||
} | ||
next(ret); | ||
return null; | ||
} | ||
function onRejected(err) { | ||
var ret; | ||
try { | ||
ret = action(name + " - runid: " + runId + " - yield " + stepId++, gen.throw).call(gen, err); | ||
} | ||
catch (e) { | ||
return reject(e); | ||
} | ||
next(ret); | ||
} | ||
function next(ret) { | ||
if (ret.done) | ||
return resolve(ret.value); | ||
// TODO: support more type of values? See https://github.com/tj/co/blob/249bbdc72da24ae44076afd716349d2089b31c4c/index.js#L100 | ||
invariant(ret.value && typeof ret.value.then === "function", "Only promises can be yielded to asyncAction, got: " + ret); | ||
return ret.value.then(onFulfilled, onRejected); | ||
} | ||
}); | ||
}; | ||
} | ||
@@ -986,17 +904,79 @@ /** | ||
if (timeout === void 0) { timeout = 0; } | ||
return new Promise(function (resolve, reject) { | ||
var timeoutHandle; | ||
var disposer = when(fn, function () { | ||
if (timeout > 0) | ||
clearTimeout(timeoutHandle); | ||
resolve(); | ||
}); | ||
if (timeout > 0) | ||
setTimeout(function () { | ||
disposer(); | ||
reject(new Error("TIMEOUT")); | ||
}, timeout); | ||
deprecated("whenAsync is deprecated, use mobx.when without effect instead"); | ||
return when(fn, { | ||
timeout: timeout | ||
}); | ||
} | ||
export { PENDING, FULFILLED, REJECTED, fromPromise, isPromiseBasedObservable, lazyObservable, fromResource, toStream, fromStream, createViewModel, whenWithTimeout, keepAlive, queueProcessor, chunkProcessor, now, NOOP, IDENTITY, invariant, deprecated, asyncAction, createAsyncActionGenerator, whenAsync }; | ||
/** | ||
* expr can be used to create temporarily views inside views. | ||
* This can be improved to improve performance if a value changes often, but usually doesn't affect the outcome of an expression. | ||
* | ||
* 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. | ||
* | ||
* @example | ||
* const Todo = observer((props) => { | ||
* const todo = props.todo; | ||
* const isSelected = mobxUtils.expr(() => props.viewState.selection === todo); | ||
* return <div className={isSelected ? "todo todo-selected" : "todo"}>{todo.title}</div> | ||
* }); | ||
* | ||
*/ | ||
function expr(expr) { | ||
if (!_isComputingDerivation()) | ||
console.warn("'expr' should only be used inside other reactive functions."); | ||
// optimization: would be more efficient if the expr itself wouldn't be evaluated first on the next change, but just a 'changed' signal would be fired | ||
return computed(expr).get(); | ||
} | ||
var memoizationId = 0; | ||
/** | ||
* Creates a function that maps an object to a view. | ||
* The mapping is memoized. | ||
* | ||
* See: https://mobx.js.org/refguide/create-transformer.html | ||
*/ | ||
function createTransformer(transformer, onCleanup) { | ||
invariant(typeof transformer === "function" && transformer.length < 2, "createTransformer expects a function that accepts one argument"); | ||
// Memoizes: object id -> reactive view that applies transformer to the object | ||
var views = {}; | ||
function createView(sourceIdentifier, sourceObject) { | ||
var latestValue; | ||
var expr = computed(function () { | ||
return (latestValue = transformer(sourceObject)); | ||
}, { | ||
name: "Transformer-" + transformer.name + "-" + sourceIdentifier | ||
}); | ||
var disposer = onBecomeUnobserved(expr, function () { | ||
delete views[sourceIdentifier]; | ||
disposer(); | ||
if (onCleanup) | ||
onCleanup(latestValue, sourceObject); | ||
}); | ||
return expr; | ||
} | ||
return function (object) { | ||
var identifier = getMemoizationId(object); | ||
var reactiveView = views[identifier]; | ||
if (reactiveView) | ||
return reactiveView.get(); | ||
// Not in cache; create a reactive view | ||
reactiveView = views[identifier] = createView(identifier, object); | ||
return reactiveView.get(); | ||
}; | ||
} | ||
function getMemoizationId(object) { | ||
if (typeof object === "string" || typeof object === "number") | ||
return object; | ||
if (object === null || typeof object !== "object") | ||
throw new Error("[mobx-utils] transform expected an object, string or number, got: " + object); | ||
var tid = object.$transformId; | ||
if (tid === undefined) { | ||
tid = ++memoizationId; | ||
addHiddenProp(object, "$transformId", tid); | ||
} | ||
return tid; | ||
} | ||
export { PENDING, FULFILLED, REJECTED, fromPromise, isPromiseBasedObservable, lazyObservable, fromResource, toStream, fromStream, createViewModel, whenWithTimeout, keepAlive, queueProcessor, chunkProcessor, now, NOOP, IDENTITY, invariant, deprecated, addHiddenProp, asyncAction, whenAsync, expr, createTransformer }; |
@@ -21,2 +21,10 @@ (function (global, factory) { | ||
} | ||
function addHiddenProp(object, propName, value) { | ||
Object.defineProperty(object, propName, { | ||
enumerable: false, | ||
writable: true, | ||
configurable: true, | ||
value: value | ||
}); | ||
} | ||
@@ -46,30 +54,20 @@ var PENDING = "pending"; | ||
} | ||
var promise = new Promise(function (resolve, reject) { | ||
origPromise.then(mobx.action("observableFromPromise-resolve", function (value) { | ||
promise.value = value; | ||
promise.state = FULFILLED; | ||
resolve(value); | ||
}), mobx.action("observableFromPromise-reject", function (reason) { | ||
promise.value = reason; | ||
promise.state = REJECTED; | ||
reject(reason); | ||
})); | ||
}); | ||
var promise = origPromise; | ||
origPromise.then(mobx.action("observableFromPromise-resolve", function (value) { | ||
promise.value = value; | ||
promise.state = FULFILLED; | ||
}), mobx.action("observableFromPromise-reject", function (reason) { | ||
promise.value = reason; | ||
promise.state = REJECTED; | ||
})); | ||
promise.isPromiseBasedObservable = true; | ||
promise.case = caseImpl; | ||
mobx.extendShallowObservable(promise, { | ||
mobx.extendObservable(promise, { | ||
value: undefined, | ||
state: PENDING | ||
}); | ||
// TODO: remove in next major | ||
Object.defineProperty(promise, "promise", { | ||
get: function () { | ||
deprecated("fromPromise().promise is deprecated. fromPromise now directly returns a promise"); | ||
return origPromise; | ||
} | ||
}); | ||
}, {}, { deep: false }); | ||
return promise; | ||
} | ||
/** | ||
* `fromPromise` takes a Promise and returns an object with 3 observable properties that track | ||
* `fromPromise` takes a Promise and returns a new Promise wrapping the original one. The returned Promise is also extended with 2 observable properties that track | ||
* the status of the promise. The returned object has the following observable properties: | ||
@@ -83,3 +81,3 @@ * - `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. | ||
* | ||
* The returned object implements `PromiseLike<TValue>`, so you can chain additional `Promise` handlers using `then`. | ||
* 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. | ||
* | ||
@@ -193,7 +191,6 @@ * Note that the status strings are available as constants: | ||
*/ | ||
function lazyObservable(fetch, initialValue, modifier) { | ||
function lazyObservable(fetch, initialValue) { | ||
if (initialValue === void 0) { initialValue = undefined; } | ||
if (modifier === void 0) { modifier = IDENTITY; } | ||
var started = false; | ||
var value = mobx.observable.shallowBox(modifier(initialValue)); | ||
var value = mobx.observable.box(initialValue, { deep: false }); | ||
var currentFnc = function () { | ||
@@ -203,3 +200,3 @@ if (!started) { | ||
fetch(function (newValue) { | ||
mobx.extras.allowStateChanges(true, function () { | ||
mobx._allowStateChanges(true, function () { | ||
value.set(newValue); | ||
@@ -308,7 +305,7 @@ }); | ||
}; | ||
var atom = new mobx.Atom("ResourceBasedObservable", function () { | ||
var atom = mobx.createAtom("ResourceBasedObservable", function () { | ||
invariant(!isActive && !isDisposed); | ||
isActive = true; | ||
subscriber(function (newValue) { | ||
mobx.extras.allowStateChanges(true, function () { | ||
mobx._allowStateChanges(true, function () { | ||
value = newValue; | ||
@@ -420,9 +417,9 @@ atom.reportChanged(); | ||
__decorate([ | ||
mobx.action | ||
mobx.action.bound | ||
], StreamListener.prototype, "next", null); | ||
__decorate([ | ||
mobx.action | ||
mobx.action.bound | ||
], StreamListener.prototype, "complete", null); | ||
__decorate([ | ||
mobx.action | ||
mobx.action.bound | ||
], StreamListener.prototype, "error", null); | ||
@@ -505,3 +502,3 @@ return StreamListener; | ||
var _this = this; | ||
this.localValues.keys().forEach(function (key) { | ||
mobx.keys(this.localValues).forEach(function (key) { | ||
var source = _this.localValues.get(key); | ||
@@ -622,18 +619,7 @@ var destination = _this.model[key]; | ||
if (onTimeout === void 0) { onTimeout = function () { }; } | ||
var done = false; | ||
var handle = setTimeout(function () { | ||
if (!done) { | ||
disposer(); | ||
onTimeout(); | ||
} | ||
}, timeout); | ||
var disposer = mobx.when(expr, function () { | ||
done = true; | ||
clearTimeout(handle); | ||
action$$1(); | ||
deprecated("whenWithTimeout is deprecated, use mobx.when with timeout option instead"); | ||
return mobx.when(expr, action$$1, { | ||
timeout: timeout, | ||
onError: onTimeout | ||
}); | ||
return function () { | ||
clearTimeout(handle); | ||
disposer(); | ||
}; | ||
} | ||
@@ -670,3 +656,3 @@ | ||
function keepAlive(_1, _2) { | ||
var computed$$1 = mobx.extras.getAtom(_1, _2); | ||
var computed$$1 = mobx.getAtom(_1, _2); | ||
if (!computed$$1) | ||
@@ -711,3 +697,3 @@ throw new Error("No computed provided, please provide an object created with `computed(() => expr)` or an object + property name"); | ||
if (debounce > 0) | ||
return mobx.autorunAsync(runner, debounce); | ||
return mobx.autorun(runner, { delay: debounce }); | ||
else | ||
@@ -765,3 +751,3 @@ return mobx.autorun(runner); | ||
if (debounce > 0) | ||
return mobx.autorunAsync(runner, debounce); | ||
return mobx.autorun(runner, { delay: debounce }); | ||
else | ||
@@ -800,3 +786,3 @@ return mobx.autorun(runner); | ||
if (interval === void 0) { interval = 1000; } | ||
if (!mobx.extras.isComputingDerivation()) { | ||
if (!mobx._isComputingDerivation()) { | ||
// See #40 | ||
@@ -835,10 +821,2 @@ return Date.now(); | ||
var __assign = (undefined && undefined.__assign) || Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
/** | ||
@@ -863,2 +841,4 @@ * `asyncAction` takes a generator function and automatically wraps all parts of the process in actions. See the examples below. | ||
* | ||
* N.B. due to a [babel limitation](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy/issues/26), in Babel generatos cannot be combined with decorators. See also [#70](https://github.com/mobxjs/mobx-utils/issues/70) | ||
* | ||
* @example | ||
@@ -883,3 +863,3 @@ * import {asyncAction} from "mobx-utils" | ||
* | ||
* mobx.useStrict(true) // don't allow state modifications outside actions | ||
* mobx.configure({ enforceActions: true }) // don't allow state modifications outside actions | ||
* | ||
@@ -910,67 +890,5 @@ * class Store { | ||
function asyncAction(arg1, arg2) { | ||
// decorator | ||
if (typeof arguments[1] === "string") { | ||
var name_1 = arguments[1]; | ||
var descriptor_1 = arguments[2]; | ||
if (descriptor_1 && descriptor_1.value) { | ||
return Object.assign({}, descriptor_1, { | ||
value: createAsyncActionGenerator(name_1, descriptor_1.value) | ||
}); | ||
} | ||
else { | ||
return Object.assign({}, descriptor_1, { | ||
set: function (v) { | ||
Object.defineProperty(this, name_1, __assign({}, descriptor_1, { value: asyncAction(name_1, v) })); | ||
} | ||
}); | ||
} | ||
} | ||
// direct invocation | ||
var generator = typeof arg1 === "string" ? arg2 : arg1; | ||
var name = typeof arg1 === "string" ? arg1 : generator.name || "<unnamed async action>"; | ||
invariant(typeof generator === "function", "asyncAction expects function as first arg, got: " + generator); | ||
return createAsyncActionGenerator(name, generator); | ||
deprecated("asyncAction is deprecated. use mobx.flow instead"); | ||
return mobx.flow.apply(null, arguments); | ||
} | ||
var generatorId = 0; | ||
function createAsyncActionGenerator(name, generator) { | ||
// Implementation based on https://github.com/tj/co/blob/master/index.js | ||
return function () { | ||
var ctx = this; | ||
var args = arguments; | ||
return new Promise(function (resolve, reject) { | ||
var runId = ++generatorId; | ||
var stepId = 0; | ||
var gen = mobx.action(name + " - runid: " + runId + " - init", generator).apply(ctx, args); | ||
onFulfilled(undefined); // kick off the process | ||
function onFulfilled(res) { | ||
var ret; | ||
try { | ||
ret = mobx.action(name + " - runid: " + runId + " - yield " + stepId++, gen.next).call(gen, res); | ||
} | ||
catch (e) { | ||
return reject(e); | ||
} | ||
next(ret); | ||
return null; | ||
} | ||
function onRejected(err) { | ||
var ret; | ||
try { | ||
ret = mobx.action(name + " - runid: " + runId + " - yield " + stepId++, gen.throw).call(gen, err); | ||
} | ||
catch (e) { | ||
return reject(e); | ||
} | ||
next(ret); | ||
} | ||
function next(ret) { | ||
if (ret.done) | ||
return resolve(ret.value); | ||
// TODO: support more type of values? See https://github.com/tj/co/blob/249bbdc72da24ae44076afd716349d2089b31c4c/index.js#L100 | ||
invariant(ret.value && typeof ret.value.then === "function", "Only promises can be yielded to asyncAction, got: " + ret); | ||
return ret.value.then(onFulfilled, onRejected); | ||
} | ||
}); | ||
}; | ||
} | ||
@@ -990,17 +908,79 @@ /** | ||
if (timeout === void 0) { timeout = 0; } | ||
return new Promise(function (resolve, reject) { | ||
var timeoutHandle; | ||
var disposer = mobx.when(fn, function () { | ||
if (timeout > 0) | ||
clearTimeout(timeoutHandle); | ||
resolve(); | ||
}); | ||
if (timeout > 0) | ||
setTimeout(function () { | ||
disposer(); | ||
reject(new Error("TIMEOUT")); | ||
}, timeout); | ||
deprecated("whenAsync is deprecated, use mobx.when without effect instead"); | ||
return mobx.when(fn, { | ||
timeout: timeout | ||
}); | ||
} | ||
/** | ||
* expr can be used to create temporarily views inside views. | ||
* This can be improved to improve performance if a value changes often, but usually doesn't affect the outcome of an expression. | ||
* | ||
* 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. | ||
* | ||
* @example | ||
* const Todo = observer((props) => { | ||
* const todo = props.todo; | ||
* const isSelected = mobxUtils.expr(() => props.viewState.selection === todo); | ||
* return <div className={isSelected ? "todo todo-selected" : "todo"}>{todo.title}</div> | ||
* }); | ||
* | ||
*/ | ||
function expr(expr) { | ||
if (!mobx._isComputingDerivation()) | ||
console.warn("'expr' should only be used inside other reactive functions."); | ||
// optimization: would be more efficient if the expr itself wouldn't be evaluated first on the next change, but just a 'changed' signal would be fired | ||
return mobx.computed(expr).get(); | ||
} | ||
var memoizationId = 0; | ||
/** | ||
* Creates a function that maps an object to a view. | ||
* The mapping is memoized. | ||
* | ||
* See: https://mobx.js.org/refguide/create-transformer.html | ||
*/ | ||
function createTransformer(transformer, onCleanup) { | ||
invariant(typeof transformer === "function" && transformer.length < 2, "createTransformer expects a function that accepts one argument"); | ||
// Memoizes: object id -> reactive view that applies transformer to the object | ||
var views = {}; | ||
function createView(sourceIdentifier, sourceObject) { | ||
var latestValue; | ||
var expr = mobx.computed(function () { | ||
return (latestValue = transformer(sourceObject)); | ||
}, { | ||
name: "Transformer-" + transformer.name + "-" + sourceIdentifier | ||
}); | ||
var disposer = mobx.onBecomeUnobserved(expr, function () { | ||
delete views[sourceIdentifier]; | ||
disposer(); | ||
if (onCleanup) | ||
onCleanup(latestValue, sourceObject); | ||
}); | ||
return expr; | ||
} | ||
return function (object) { | ||
var identifier = getMemoizationId(object); | ||
var reactiveView = views[identifier]; | ||
if (reactiveView) | ||
return reactiveView.get(); | ||
// Not in cache; create a reactive view | ||
reactiveView = views[identifier] = createView(identifier, object); | ||
return reactiveView.get(); | ||
}; | ||
} | ||
function getMemoizationId(object) { | ||
if (typeof object === "string" || typeof object === "number") | ||
return object; | ||
if (object === null || typeof object !== "object") | ||
throw new Error("[mobx-utils] transform expected an object, string or number, got: " + object); | ||
var tid = object.$transformId; | ||
if (tid === undefined) { | ||
tid = ++memoizationId; | ||
addHiddenProp(object, "$transformId", tid); | ||
} | ||
return tid; | ||
} | ||
exports.PENDING = PENDING; | ||
@@ -1025,5 +1005,7 @@ exports.FULFILLED = FULFILLED; | ||
exports.deprecated = deprecated; | ||
exports.addHiddenProp = addHiddenProp; | ||
exports.asyncAction = asyncAction; | ||
exports.createAsyncActionGenerator = createAsyncActionGenerator; | ||
exports.whenAsync = whenAsync; | ||
exports.expr = expr; | ||
exports.createTransformer = createTransformer; | ||
@@ -1030,0 +1012,0 @@ Object.defineProperty(exports, '__esModule', { value: true }); |
{ | ||
"name": "mobx-utils", | ||
"version": "3.2.2", | ||
"version": "4.0.0-beta.2", | ||
"description": "Utility functions and common patterns for MobX", | ||
@@ -13,3 +13,4 @@ "main": "mobx-utils.umd.js", | ||
"build": "tsc -p src && rollup lib/mobx-utils.js -e mobx -g mobx:mobx -o mobx-utils.umd.js -f umd --name mobxUtils && rollup lib/mobx-utils.js -e mobx -o mobx-utils.module.js -f es", | ||
"test": "npm run build && tsc -p test && tape test/*.js .test-ts/*.js | faucet", | ||
"watch": "yarn jest --watch", | ||
"test": "yarn jest", | ||
"lint:js": "eslint ./test", | ||
@@ -19,3 +20,3 @@ "lint:ts": "tslint ./src/*.ts", | ||
"prepublish": "npm run build && npm run build-docs", | ||
"coverage": "npm run build && tsc -p test && istanbul cover tape test/*.js .test-ts/*.js && cat ./coverage/lcov.info|coveralls", | ||
"coverage": "yarn jest --coverage", | ||
"build-docs": "npm run build && documentation readme lib/mobx-utils.js --section API" | ||
@@ -38,2 +39,3 @@ }, | ||
"devDependencies": { | ||
"@types/jest": "^22.2.0", | ||
"@types/tape": "^4.2.30", | ||
@@ -45,9 +47,10 @@ "babel-eslint": "^7.1.0", | ||
"faucet": "0.0.1", | ||
"istanbul": "^0.3.21", | ||
"jest": "^22.4.2", | ||
"lint-staged": "^4.2.3", | ||
"mobx": "^3.0.0", | ||
"lodash.intersection": "^4.4.0", | ||
"mobx": "^4.0.0-beta.1", | ||
"prettier": "^1.7.2", | ||
"rollup": "^0.50.0", | ||
"rxjs": "^5.0.2", | ||
"tape": "^4.2.2", | ||
"ts-jest": "^22.4.1", | ||
"tslint": "^3.15.1", | ||
@@ -59,3 +62,3 @@ "tslint-eslint-rules": "^2.1.0", | ||
"peerDependencies": { | ||
"mobx": "^3.0.0" | ||
"mobx": "4.0.0-beta.2" | ||
}, | ||
@@ -70,3 +73,25 @@ "keywords": [ | ||
"state management" | ||
] | ||
} | ||
], | ||
"jest": { | ||
"transform": { | ||
"^.+\\.ts?$": "ts-jest" | ||
}, | ||
"testRegex": "test/.*\\.(t|j)sx?$", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js", | ||
"jsx", | ||
"json" | ||
], | ||
"testPathIgnorePatterns": [ | ||
"/node_modules/", | ||
"/lib/", | ||
"/coverage/", | ||
"/\\./" | ||
], | ||
"watchPathIgnorePatterns": [ | ||
"<rootDir>/node_modules/" | ||
] | ||
} | ||
} |
@@ -27,3 +27,3 @@ # MobX-utils | ||
`fromPromise` takes a Promise and returns an object with 3 observable properties that track | ||
`fromPromise` takes a Promise and returns a new Promise wrapping the original one. The returned Promise is also extended with 2 observable properties that track | ||
the status of the promise. The returned object has the following observable properties: | ||
@@ -39,3 +39,3 @@ | ||
The returned object implements `PromiseLike<TValue>`, so you can chain additional `Promise` handlers using `then`. | ||
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. | ||
@@ -124,3 +124,2 @@ Note that the status strings are available as constants: | ||
- `initialValue` **T** optional initialValue that will be returned from `current` as long as the `sink` has not been called at least once (optional, default `undefined`) | ||
- `modifier` | ||
@@ -499,2 +498,4 @@ **Examples** | ||
N.B. due to a [babel limitation](https://github.com/loganfsmyth/babel-plugin-transform-decorators-legacy/issues/26), in Babel generatos cannot be combined with decorators. See also [#70](https://github.com/mobxjs/mobx-utils/issues/70) | ||
**Parameters** | ||
@@ -527,3 +528,3 @@ | ||
mobx.useStrict(true) // don't allow state modifications outside actions | ||
mobx.configure({ enforceActions: true }) // don't allow state modifications outside actions | ||
@@ -569,1 +570,35 @@ class Store { | ||
Returns **any** Promise for when an observable eventually matches some condition. Rejects if timeout is provided and has expired | ||
## expr | ||
expr can be used to create temporarily views inside views. | ||
This can be improved to improve performance if a value changes often, but usually doesn't affect the outcome of an expression. | ||
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. | ||
**Parameters** | ||
- `expr` | ||
**Examples** | ||
```javascript | ||
const Todo = observer((props) => { | ||
const todo = props.todo; | ||
const isSelected = mobxUtils.expr(() => props.viewState.selection === todo); | ||
return <div className={isSelected ? "todo todo-selected" : "todo"}>{todo.title}</div> | ||
}); | ||
``` | ||
## createTransformer | ||
Creates a function that maps an object to a view. | ||
The mapping is memoized. | ||
See: <https://mobx.js.org/refguide/create-transformer.html> | ||
**Parameters** | ||
- `transformer` | ||
- `onCleanup` |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
225131
66
599
18
4713
2