Giter Club home page Giter Club logo

mobx-async-actions's Introduction

Async in MobX

I've always loved MobX because of it's lack of boilerplate in comparison to Redux. It just seems so effortless to modify state... so how does it fare with Async code?

In Redux you'd reach for something like thunk, but in MobX there are a few easy ways you can deal with asynchronous code.

This tutorial explains how to run Async code in both MobX 3 and MobX 4.

The Incorrect Way

The funny thing about MobX is that the code below will probably work, but isn't recommended. That's because action functions are the only place you are supposed to modify the state. Here we are modifying it in the function which gets called on successful promise resolution, not in the action itself.

@action
loadWeather = city => {
  fetch(
    `https://abnormal-weather-api.herokuapp.com/cities/search?city=${city}`
  )
    .then(response => response.json())
    .then(data => {
      this.weatherData = data;
    });
};

Avoid the Incorrect Way

In MobX 4:

By importing the configure function and telling it to enforceActions, you can have MobX throw an error if you happen to modify the state outside of an action.

import { configure } from "mobx";
configure({ enforceActions: true });

In MobX 3:

By importing the useStrict function, you can have MobX throw an error if you happen to modify the state outside of an action.

import { useStrict } from "mobx";
useStrict(true);

An Action Modifies State

Let's correct the code in "The Incorrect Way". We'll move the code that modifies the state into its own function, and make that the action instead of the code which performs the fetch.

// no longer an action
loadWeather = city => {
  fetch(
    `https://abnormal-weather-api.herokuapp.com/cities/search?city=${city}`
  )
    .then(response => response.json())
    .then(data => {
      this.setWeatherData(data);
    });
};

// becomes the action, purely to set the data
@action
setWeatherData = data => {
  this.weatherData = data;
};

Using runInAction

You can turn a callback (or promise resolve function) into an action by using the runInAction function.

import { runInAction } from "mobx";

// ...

loadWeatherRunInThen = city => {
  fetch(`https://abnormal-weather-api.herokuapp.com/cities/search?city=${city}`)
    .then(response => response.json())
    .then(data => {
      // now we can turn this part of our code into an action
      // this will allow us to modify state
      runInAction(() => {
        this.weatherData = data;
      });
    });
};

Here is the same example but using async await instead of then callback functions. Async/Await code seems synchronous because it reads in order like synchronous code, but it's really just syntactic sugar over the then approach.

loadWeatherRunInAsync = async city => {
  const response = await fetch(
    `https://abnormal-weather-api.herokuapp.com/cities/search?city=${city}`
  );
  const data = await response.json();

  runInAction(() => {
    this.weatherData = data;
  });
};

Async and Generators

As of MobX 4 there is a function called flow part of MobX Core, while in MobX 3 there is a function called asyncAction in the mobx-utils package that lets you solve the "async issue" in a slightly different way.

The * is important as it denotes the function as a generator function, whereas yield gives control to the iterator. We'll pass our generator function to the flow (or asyncAction) function, and every place there is supposed to be await in a typical Async/Await scenario, we'll use the yield keyword instead.

import { flow } from "mobx";
// MobX 3
// import {asyncAction} from "mobx-utils"

// ...

loadWeatherGenerator = flow(function*(city) {
  const response = yield fetch(
    `https://abnormal-weather-api.herokuapp.com/cities/search?city=${city}`
  );
  const data = yield response.json();
  this.weatherData = data;
});

You'll notice above I didn't use an arrow function... which is because I don't think there is a way to do generator functions with arrow functions, at least in Babel. This should be possible in Typescript.

A Babel Plugin

If writing runInAction code annoys you and brings you back to the thunk/redux boilerplate, try out the mobx-deep-action plugin, which automatically wraps nested functions in action functions. This is part of the mobxjs organization, so it should have pretty good support going forward.

Conclusion

Visit the MobX documentation for the ultimate guide to writing async code in MobX. In this article we covered the incorrect way, the runInAction approach and the flow (or asyncAction) with generator function approach.

Alternatively you can use a Babel plugin to automatically wrap Async/Await code in runInAction functions for you.

mobx-async-actions's People

Contributors

leighhalliday avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.