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 an Observable that lets us subscribe to it and then change the value of it.
The observable Function
The Mobx observable
function takes an object. It’s also available in decorator form where we can set the value of it directly.
It can be used as follows:
observable(value)
@observable classProperty = value
It returns various kinds of values depending on what value is passed in. The value
can be JavaScript primitive values, references, plain objects, class instances, arrays, and maps.
There’re some conversion rules applied to values that are passed into the observable
function. They’re the following:
- If
value
is an ES6Map
, then a new Observable Map will be returned. Observable maps are very useful if we want to react to changes in a specific entry, and addition or removal of entries. - If
value
is an ES6Set
, then a new Observable Set will be returned. - If
value
is an array, then a new Observable array will be returned. - If
value
is an object without a prototype, all its current properties will be made observable - If
value
is an object with a prototype, a JavaScript primitive or function, theobservable
will throw. We should use Boxed Observable observables instead.
For example, we can use observable
as follows:
import { observable } from "mobx";
const map = observable.map({ foo: "value" });
map.observe(({ oldValue, newValue }) => console.log(oldValue, newValue));
map.set("foo", "new value");
In the code above, we have the observable.map
function to create an Observable Map.
Then we attach a listener to it to watch the values with the observe
function. The listener gives us an object with the oldValue
and newValue
properties so we can retrieve them.
When we call:
map.set("foo", "new value");
then we’ll see the values logged by the listener.
We can also do something similar with arrays:
import { observable } from "mobx";
const array = observable([1, 2, 3]);
array.observe(({ oldValue, newValue }) => console.log(oldValue, newValue));
array[1] = 5;
We passed in an array to the observable
function which returns an Observable array. Then we can call observe
on it to watch its values like before.
Then when we make changes to array
, the listener then we pass into observe
will log the new and old values.
To make primitives observable, we can use the box
method as follows:
import { observable } from "mobx";
const num = observable.box(3);
num.observe(({ oldValue, newValue }) => console.log(oldValue, newValue));
num.set(10);
In the code above, we created an observable primitive with the box
method. The code for observing the value change is the same as before.
Then we can use set
to set a new value for the num
Observable primitive.
The @observable Decorator
If our codebase has support for ES7 or TypeScript, then we can use the @observable
decorator to make class properties observable.
We can use them as follows:
import { observable, computed } from "mobx";
class Person {
@observable firstName = "Jane";
@observable lastName = "Smith";
@computed get fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
const person = new Person();
console.log(person.firstName);
console.log(person.lastName);
console.log(person.fullName);
In the code above, we created the Person
class which has Observable properties as indicated by using the observable
decorator. We also have a computed
property fullName
which is a getter.
Then we create a new Person
instance and we can log the values.
We can also set the values by assigning a value as usual.
To use decorators, we can use a build system like Parcel and then add the @babel/core
, @babel/plugin-proposal-class-properties
, @babel/plugin-proposal-decorators
, and @babel/preset-env
packages and all them to .babelrc
in the plugins
section as follows:
{
"presets": [
"@babel/preset-env"
],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
[
"@babel/plugin-proposal-class-properties",
{
"loose": true
}
]
]
}
Conclusion
We can create Observable values with the observable
object. It can be used with various kinds of objects as long as it’s used with the correct method to create an Observable value.
Then we can use the observe
method to observe the value of the returned Observable and manipulate it.
We can also use the observable
decorator with classes to create a class with Observable properties.
To use decorators we either use Babel or TypeScript.