Creating observables
The simplest way to create an observable is to use the observable() function. Take a look at the following:
const item = observable({
name: 'Party Balloons',
itemId: '1234',
quantity: 2,
price: 10,
coupon: {
code: 'BIGPARTY',
discountPercent: 50
}
});
item is now an observable object and will start tracking changes to its properties. You can use this object as a regular JavaScript object without any special API to get or set its values. In the preceding snippet, you can also create an observable item using observable.object().
In the following snippet, we can see simple mutations made to the observables, like any regular JavaScript code:
// Set values
item.quantity += 3;
item.name = 'Small Balloons';
// Get values
console.log(`Buying ${item.quantity} of ${item.name}`);
Observable objects only track the properties provided in the initial value given to observable() or observable.object(). This means if you add new properties later, they will not become observable automatically. This is an important characteristic to remember about observable objects. They are like records or classes with a fixed set of attributes. If you do need dynamic tracking of properties, you should consider using observable maps; these will be covered further ahead in the chapter.
The observable() function automatically converts an object, an array, or a map into an observable entity. This automatic conversion is not applied for other types of data—such as JavaScript primitives (number, string, boolean, null, undefined), functions, or for class- instances (objects with prototypes). So, if you call observable(20), it will fail with an error, as shown here:
Error: [mobx] The provided value could not be converted into an observable. If you want just create an observable reference to the object use 'observable.box(value)'
As suggested in the error, we have to use the more specialized observable.box() to convert primitive values into an observable. Observables that wrap primitives, functions, or class-instances are called boxed observables. Take a look at this:
const count = observable.box(20);
// Get the count
console.log(`Count is ${count.get()}`);
// Change count
count.set(22);
We have to use the get() and set() methods of a boxed observable instead of directly reading or assigning to it. These methods give us the observability that is inherent to MobX.
Besides objects and singular values, you can also create observables out of arrays and maps. They have a corresponding API, as can be seen in this table:
As we mentioned earlier, observable() will automatically convert an object, array, or a map into an observable. It is shorthand for observable.object(), observable.array(), or observable.map(), respectively. For primitives, functions, and class-instances, you should use the observable.box() API. Although, in practice, the use of observable.box() is fairly rare. It is more common to use observable.object(), observable.array(), or observable.map().