MobX works like a spreadsheet, everything is derived from state. Even effects with things like autorun
.
The problem for me is that it's unclear when to run an effect based on some event firing, rather than based on a state-change (using autorun
or something like that).
For instance let's say I need to fetch some milk (an action that causes an HTTP request - hence an effect) after 3 specific conditions are met (derived from state). I can use when
to run this side-effect:
when(
() => {
if (
self.isOnConfirmationPage &&
paymentStore.successfullySubscribed &&
calendarStore.isFriday
) {
return true;
}
return false;
},
() => self.fetchMilk(),
);
A new requirement comes in asking me to add some logging. Specifically I need to call a track()
service (another HTTP request hence another effect), but this track()
service depends on the data returned by the fetchMilk()
service.
Now I could simply add .then()
to my fetchMilk:
self.fetchMilk().then(milkResponse => self.track(
milkResponse.user,
milkResponse.order
))
Going back to the title of my question, this to me is "reacting based on an event" - the event in this case being the response by the fetchMilk()
service.
What if I simply react based on the state-change rather than the event?
This means track()
needs to be also placed in a reaction, and since it depends on the response of fetchMilk()
I can simply store this in a MobX store and react upon it:
when(
() => {
if (
self.milk.user &&
self.milk.order
) {
return true;
}
return false;
},
() => self.track(self.milk.user, self.milk.order),
);
Note that instead of using a "promise-based" flow for handling async behavior, I'm simply reacting based on values changing.
My question: which of these two options should I use? What are the benefits/cons of each approach? Is it safe to model async behavior using the 2nd approach?
I would go for the promise.then()
version, simply because it is easier to follow the code flow.
There is no rule that says that everything in the app must be set up so that all code is driven by mobx actions and reactions.
When you want a change in the app to be broadcasted to the world, then you enter the mobx world.
When you think about it, mobx is just like an event dispatcher, but the event dispatch code (subscriptions and notifications) are hidden behind mobx magic. So the best option in my experience is to do all the async work you need to do, and then notify mobx of the changes.
If you take a look at the official documentation it has an example of using asynchronous code, which does exactly that.