I started using MobX recently, and I came across the reaction
concept. I understand reactions
as functions, that runs side-effects. It is up to me, what side-effects are. I use reaction to update my MobX state. If you check my code below, I have a state for items (ingredients). What I want to do, is load ingredients from my localStorage (function getIngredients
) and display them in my React. So far so good. Then, whenever I update ingredient (change name, price, weight - it is editable by form), I want to store this change in localStorage (function putIngredient
), and then update my @observable ingredients
accordingly (so later, when I get rid of localStorage
and replace it with database, I keep track of my changes in MobX). I thought using MobX reaction
is pretty nice idea how to handle it, but when I tried to run updateIngredients
function, I got an following error:
Encountered an uncaught exception that was thrown by a reaction or observer component, in: 'Reaction[Reaction@1]' Error: "ingredients" is read-only
You can see, that inside updateIngredients
function, there is one line commented. If I uncomment this line and comment the previous one (ingredients = ingredients.map(i => i.id === ingredient.id ? ingredient : i);
), script will work. I thought, I can edit observable
variables simply by reassigning them new values. Actually, I already did it like that in getIngredients
function, where getIngredients
function returns new array. So what is the trick here? Why I am getting this error?
import { observable, action, reaction } from 'mobx';
import { getIngredients, putIngredient } from './localStorage';
class Ingredients {
@observable ingredients = [];
@observable updatedIngredient = null;
@action.bound getIngredients(opts = {}) {
this.ingredients = getIngredients({ ...opts });
}
@action.bound async putIngredient(ingredient) {
putIngredient(ingredient);
this.updatedIngredient = ingredient;
}
@action.bound updateIngredients(ingredient) {
const { ingredients } = this;
ingredients = ingredients.map(i => i.id === ingredient.id ? ingredient : i);
// ingredients.replace(ingredients.map(i => i.id === ingredient.id ? ingredient : i));
}
}
const IngredientsStore = new Ingredients();
reaction(
() => IngredientsStore.updatedIngredient,
(updatedIngredient) => {
if (updatedIngredient) {
IngredientsStore.updateIngredients(updatedIngredient);
}
}
)
export default IngredientsStore;