Actions
Although you can change an observable directly, it is highly recommended that you use actions to do it. If you remember, in the previous chapter, we saw that actions are the ones that cause a state-change. The UI simply fires the actions and expects some observables to be mutated. Actions hide the details of how the mutation should happen or what observables should be affected.
The diagram below is a reminder that UI can modify the State only via an Action:
Actions introduce vocabulary into the UI and give declarative names to the operations that mutate the state. MobX embraces this idea completely and makes actions a first-class concept. To create an action, we simply wrap the mutating function inside the action() API. This gives us back a function that can be invoked just like the original passed-in function. Take a look at this code block:
import { observable, action } from 'mobx';
const cart = observable({
items: [],
modified: new Date(),
});
// Create the actions
const addItem = action((name, quantity) => {
const item = cart.items.find(x => x.name === name);
if (item) {
item.quantity += 1;
} else {
cart.items.push({ name, quantity });
}
cart.modified = new Date();
});
const removeItem = action(name => {
const item = cart.items.find(x => x.name === name);
if (item) {
item.quantity -= 1;
if (item.quantity <= 0) {
cart.items.remove(item);
}
cart.modified = new Date();
}
});
// Invoke actions
addItem('balloons', 2);
addItem('paint', 2);
removeItem('paint');
In the preceding snippet, we have introduced two actions: addItem() and removeItem(), which add and remove an item to and from the cart observable. Since action() returns a function that forwards arguments to the passed-in function, we can invoke addItem() and removeItem() with the required arguments.
Besides improving the readability of the code, actions also boost performance of MobX. By default, when you modify an observable, MobX will immediately fire a notification for the change. If you are modifying a bunch of observables together, you would rather fire the change notifications after all of them are modified. This would reduce the noise of too many notifications and also treat the set of changes as one atomic transaction. These are, in essence, the core responsibilities of an action().