Leonardo Maldonado Fullstack developer. JavaScript, React, TypeScript, GraphQL.

What’s new in MobX 6.0

4 min read 1180

There are a lot of requirements needed to make a library well known and commonly used in React. Especially with the state-management libraries, the core concepts that the library is built upon can make a total difference in whether developers are going to adopt the framework or not.

One of the reasons why MobX was adopted by the community and used in a lot of different projects is because of its philosophy. A very straightforward, simple, robust, and unopinionated library, MobX is only getting better as time passes. A state-management library that is almost boilerplate free makes the life of developers easier, and that’s one of the major advantages of MobX over other conventional state-management libraries in React.

MobX is one of the most used state-management libraries in React and it now has a new version, introducing a few changes in order to make the library more simple, robust, and scalable. MobX is not a library exclusive for React apps, it can be used with other JavaScript libraries and frameworks as well.

We will explore what’s new in the MobX 6.0 version and see how we can migrate our code from older versions to the newest version.

MobX

In case you haven’t tried out MobX yet, I will show you the concepts that you should have in mind about how MobX really works. There are a lot of advantages of using MobX in React applications in order to make it more scalable, robust, and straightforward. From the docs.

Anything that can be derived from the application state, should be. Automatically.

Basically, MobX has four important concepts that you should have in mind:

Observables are responsible for keeping track of data structures (classes, objects, arrays, references). Whenever a value in our store changes, MobX will keep track of the new value for us:

import { observable } from "mobx";
class Store {
  @observable counter = 0;
}

Actions are responsible for modifying our state. Whenever we want to update a value, we need to perform an action. Actions always happen in response to an event, a button clicked or a form submitted, for example:

import { observable } from "mobx";
class Store {
  @observable counter = 0;
  @action increment() {
    this.counter++;
  }

  @action decrement() {
    this.counter--;
  }
}

Actions are responsible for changing and modifying our observables. In MobX, by default, there’s no way to update the state outside an action. This rule makes your codebase and state more predictable, bug-free, and robust.

Computed values are used for deriving information for observables. They are a function that keeps track of your state, whenever it changes, their returned values will change as well:

import { observable } from "mobx";
class Store {
  @observable counter = 0;
  @action increment() {
    this.counter++;
  }

  @action decrement() {
    this.counter--;
  }

  @computed counterMoreThan10() {
    return this.counter > 10;
  }
}

Reactions are pretty similar to computed values but the difference is that it triggers side-effects and occurs when observables change, the goal of having reactions is to perform side-effects automatically.

Now that we know a little bit about the core concepts of MobX, let’s understand what has really changed in the 6.0 version and how its API has become easier and powerful to use.

MobX 6.0

A few months ago the proposal of MobX 6 was created by the creator of the library Michel Weststrate. As many proposals for new versions, there was a lot of discussion about what should be included and what should be dropped in the new upcoming version of MobX.

These are the changes and what’s new in the new MobX 6.0:

Decorators

A lot of projects are known for making use of JavaScript decorators, such as Angular, NestJS, and of course MobX. Decorators are currently at stage 2 proposal and it doesn’t seem like it will be supported anytime soon.

One of the most debated points in the new 6.0 version was if decorators should be dropped in order to gain a few advantages like:

  • More compatibility with standard modern JavaScript
  • Work out of the box in most setups (e.g. create-react-app)
  • Reduce bundle size

Decorators are not required in MobX anymore, although the library still could be used without decorators in the previous versions, a lot of developers didn’t like MobX at first just because the use of decorators.

For example, this is an example of MobX in the previous versions making use of decorators:

import { observable } from "mobx";
class Store {
  @observable counter = 0;
  @action increment() {
    this.counter++;
  }

  @action decrement() {
    this.counter--;
  }

  @computed counterMoreThan10() {
    return this.counter > 10;
  }
}

This is an example of MobX in the 6.0 version:

import {
  observable,
  action,
  computed,
  makeObservable
} from "mobx";
class Store {
  counter = 0;
  constructor() {
    makeObservable(this, {
      counter: observable,
      increment: action,
      decrement: action,
      counterMoreThan10: computed
    });
  }
  increment() {
    this.counter++;
  }
  decrement() {
    this.counter--;
  }
  get counterMoreThan10() {
    return this.counter > 10;
  }
}

For some developers, the syntax without decorators is cleaner and simpler, for others, the developer experience got worse.

The fact is that the makeObservable utility function makes the integration easier, there’s no longer a need to download and use a lot of different packages just because of decorators.

The makeObservable utility function should be wrapped inside the constructor method and for each property of the state, in order to make it observable, should be specified using an annotation:

constructor() {
  makeObservable(this, {
    counter: observable,
    increment: action,
    decrement: action,
    counterMoreThan10: computed
  });
}

Decorators can still be used in MobX, but we will still need to add a constructor to the class, use the makeObservable utility function and we can omit the second argument:

class Store {
  @observable counter = 0;
  constructor() {
    makeObservable(this);
  }
  @action increment() {
    this.counter++;
  }
  @action decrement() {
    this.counter--;
  }
  @computed get counterMoreThan10() {
    return this.counter > 10;
  }
}

makeAutoObservable

Introduced in the 6.0 version, the makeAutoObservable utility function is way more powerful than the makeObservable utility function.

It makes all properties observable by default, although you still can override with specific annotations:

class Store {
  counter = 0;
  constructor() {
    makeAutoObservable(this);
  }
  increment() {
    this.counter++;
  }
  decrement() {
    this.counter--;
  }
  get counterMoreThan10() {
    return this.counter > 10;
  }
}

The makeAutoObservable is really one of the most important and awesome changes in the new version of MobX. It makes things easier for developers, removing the need to mention each observable, action, and computed value that they might have inside a store.

Proxies

MobX has a few really different ways for configuration and in order to use it in some JavaScript engines, there are a few things to be done.



In MobX 5.0, support for proxies was required and this requirement was causing a problem of support in some JavaScript engines, especially for Internet Explorer and React Native (depending on the engine).

Under the hood, MobX uses proxies to make arrays and plain objects observable. The problem is that it can cause some problems for some JavaScript engines that don’t support proxies. In the MobX 6.0, proxies are still supported and required but now there’s a way to disable it by using the configure function:

import { configure } from "mobx";
configure({     
  useProxies: "never"
})

Conclusion

It’s not an easy job to maintain and keep updating a library for many years, and the MobX community deserves the credit for it. The library keeps getting better and better and following its philosophy since the beginning, “Anything that can be derived from the application state, should be derived. Automatically”.

Cut through the noise of traditional React error reporting with LogRocket

LogRocket is a React analytics solution that shields you from the hundreds of false-positive errors alerts to just a few truly important items. LogRocket tells you the most impactful bugs and UX issues actually impacting users in your React applications. LogRocket automatically aggregates client side errors, React error boundaries, Redux state, slow component load times, JS exceptions, frontend performance metrics, and user interactions. Then LogRocket uses machine learning to notify you of the most impactful problems affecting the most users and provides the context you need to fix it.

Focus on the React bugs that matter — .

Leonardo Maldonado Fullstack developer. JavaScript, React, TypeScript, GraphQL.

Leave a Reply