UNPKG

mobx-utils

Version:

Utility functions and common patterns for MobX

108 lines (107 loc) 4.78 kB
var __assign = (this && this.__assign) || function () { __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; }; return __assign.apply(this, arguments); }; import { flow } from "mobx"; import { deprecated } from "./utils"; /** * _deprecated_ this functionality can now be found as `flow` in the mobx package. However, `flow` is not applicable as decorator, where `asyncAction` still is. * * * * `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 together. * 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. * * 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 * 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") * }) * * @example * import {asyncAction} from "mobx-utils" * * mobx.configure({ enforceActions: "observed" }) // don't allow state modifications outside actions * * class Store { * \@observable githubProjects = [] * \@observable = "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" * } * } * } * * @export * @returns {Promise} */ 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: flow(descriptor_1.value), }); } else { return Object.assign({}, descriptor_1, { set: function (v) { Object.defineProperty(this, name_1, __assign(__assign({}, descriptor_1), { value: flow(v) })); }, }); } } // direct invocation var generator = typeof arg1 === "string" ? arg2 : arg1; var name = typeof arg1 === "string" ? arg1 : generator.name || "<unnamed async action>"; deprecated("asyncAction is deprecated. use mobx.flow instead"); return flow(generator); // name get's dropped.. }