Categories
Mobx

Create Mobx Observable Objects and Arrays

Spread the love

Mobx is a state management solution for JavaScript apps. It lets us observe values from a store and then set the values, which will be immediately reflected in the store.

In this article, we’ll look at how to create Observable objects with Mobx.

Observable Objects

Mobx provides us with the observable.object method, which can be called as follows:

observable.object(props, decorators?, options?)

If a plain JavaScript object is passed to the observable then all properties inside will be cloned and made observable.

A plain object is an object that wasn’t created from a constructor but has Object as its prototype or no prototype.

observable is applied recursively by default, so if the encountered value is an object or array, the value will also be passed through observable .

We can use the observable.object method as follows:

import { observable, autorun, observe, action } from "mobx";

const person = observable(
  {
    firstName: "Jane",
    lastName: "Smith",
    get fullName() {
      return `${this.firstName}, ${this.lastName}`;
    },
    setAge(age) {
      this.age = age;
    }
  },
  {
    setAge: action
  }
);

observe(person, ({ newValue, oldValue }) => console.log(newValue, oldValue));
person.setAge(20);

We created the Observable person object with the observable function, which takes a plain object as the first argument. Then we set the setAge method in the object as an action with the second object.

We can then observe value changes with the observe method, which takes the Observable person object as the first argument and a change listener as the second argument.

Then when we run:

person.setAge(20);

the listener that we passed into observe will run.

In MobX 4 or lower, when we pass objects into observable, only propeties that exist at the time of making the object observable will be observable. Properties that are added to the object at a later time won’t be observable unless set or extendObservable os used.

Only plain objects will be made observable. For non-plain objects, it’s considered the responsibility of the constructor to initialize the observable properties.

We can either use the @observale annotation or the extendObservable function.

Property getters will be automatically turned into derived properties.

oberservable is applied recursively to the whole object automatically on instantiation and also when new values are assigned to the observable properties. It’s won’t apply observable recursively to non-plain objects.

We can pass in { deep: false } to observable ‘s 3rd argument to disable automatic conversion of property values.

Also, we can use the autorun function to watch the values that are changed as follows:

import { observable, autorun, action } from "mobx";

const person = observable(
  {
    firstName: "Jane",
    lastName: "Smith",
    get fullName() {
      return `${this.firstName}, ${this.lastName}`;
    },
    setAge(age) {
      this.age = age;
    }
  },
  {
    setAge: action
  },
  {
    name: "person"
  }
);

autorun(() => console.log(person.age));
autorun(() => console.log(person.firstName));

person.setAge(20);
person.firstName = "Joe";

In the code above, we’ll see the callbacks we passed into autorun run when we update person.age via setAge or when we update a property directly as we did with firstName .

Observable Arrays

We can use the observable.array method to create an Observable array. It takes an array as the first argument.

For example, we can use it as follows:

import { observable, autorun } from "mobx";

const fruits = observable(["apple", "orange"]);

autorun(() => console.log(fruits.join(", ")));

fruits.push("grape");
fruits[0] = "pear";

In the code above, we passed in array to observable . Then we runautorun with a callback that runs every time fruits change.

Then when we run the array operations on fruits , we get the latest value in the callback we passed into autorun .

The following methods are also available on observable arrays:

  • intercept(interceptor) — intercept array change operations
  • observe(listener, fireImmediately? = false) — listen to array changes
  • clear() — remove all entries from an array
  • replace(newItems) — replace all entries with new ones.
  • find(predicate: (item, index, array) => boolean, thisArg?) — same as the usual Array.prototype.find method
  • findIndex(predicate: (item, index, array) => boolean, thisArg?) — same as the usual Array.prototype.findIndex method
  • remove(value) — remove a single item by value from an array. It returns true is the item is found and removed

We can pass in { deep: false } as the second argument of observable.array to prevent setting items to be observable recursively.

Also, we can pass in { name: "my array" } as the second argument to add a name for debugging purposes.

Conclusion

We can create Observable objects with the observable.object and the observable.array method to create Observable arrays.

We can watch for value changes with autorun which will give us the latest values as the observable object changes.

Also, we can set various options to control how the observable values will be converted.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *