Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

actionAsync (red X is coveralls) #217

Merged
merged 13 commits into from
Oct 13, 2019
Merged

actionAsync (red X is coveralls) #217

merged 13 commits into from
Oct 13, 2019

Conversation

xaviergonz
Copy link
Contributor

@xaviergonz xaviergonz commented Oct 6, 2019

Related to mobxjs/mobx#2118

I'd like to name it asyncAction instead, but that one is taken (although deprecated), so I named it backwards

actionAsync

Alternative syntax for async actions, similar to flow but more compatible with
Typescript typings. Not to be confused with asyncAction, which is deprecated.

actionAsync can be used either as a decorator or as a function.
It takes an async function that internally must use await task(promise) rather than
the standard await promise.

When using the mobx devTools, an asyncAction will emit action events with names like:

  • "fetchUsers - runid 6 - step 0"
  • "fetchUsers - runid 6 - step 1"
  • "fetchUsers - runid 6 - step 2"

The runId represents the action instance. In other words, if fetchUsers is invoked
multiple times concurrently, the events with the same runid belong together.
The step number indicates the code block that is now being executed.

Examples

import {actionAsync, task} from "mobx-utils"

let users = []

const fetchUsers = actionAsync("fetchUsers", async (url) => {
  const start = Date.now()
  // note the use of task when awaiting!
  const data = await task(window.fetch(url))
  users = await task(data.json())
  return start - Date.now()
})

const time = await fetchUsers("http://users.com")
console.log("Got users", users, "in ", time, "ms")
import {actionAsync, task} from "mobx-utils"

mobx.configure({ enforceActions: "observed" }) // don't allow state modifications outside actions

class Store {
  @observable githubProjects = []
  @state = "pending" // "pending" / "done" / "error"

  @actionAsync
  async fetchProjects() {
    this.githubProjects = []
    this.state = "pending"
    try {
      // note the use of task when awaiting!
      const projects = await task(fetchGithubProjectsSomehow())
      const filteredProjects = somePreprocessing(projects)
      // the asynchronous blocks will automatically be wrapped actions
      this.state = "done"
      this.githubProjects = filteredProjects
    } catch (error) {
       this.state = "error"
    }
  }
}

As for changes from the last iteration now it uses a global awaiter "task", which allows for a decorator version.

@coveralls
Copy link

coveralls commented Oct 6, 2019

Coverage Status

Coverage decreased (-0.7%) to 93.636% when pulling a37d378 on action-async into 75733b1 on master.

@xaviergonz xaviergonz self-assigned this Oct 6, 2019
@xaviergonz xaviergonz changed the title actionAsync actionAsync (red X is coveralls) Oct 7, 2019
Copy link
Member

@mweststrate mweststrate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM to me! Looks really solid :)

@xaviergonz
Copy link
Contributor Author

Thanks! just improved it by fixing some edge cases such as recursivity and making sure dangling promises never leave a stale action started.

I was just wondering, should this replace "asyncAction", or just use the new "actionAsync" name?

@xaviergonz xaviergonz merged commit 41246ea into master Oct 13, 2019
@mweststrate
Copy link
Member

Released as 5.5.0!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants