As per the official mobx docs, i understood that when we wrap react event handlers with @action, we should see that mobx derived fns should be batched - computed fns, reaction executor fns, autorun fns.
If we see that as an example it goes like this:
Case 1: When react event handler is wrapped with action
import React, { Component } from "react";
import { render } from "react-dom";
import { observable, action, computed, autorun } from "mobx";
import { observer } from "mobx-react";
class Person {
@observable firstName = "Ramu";
@observable lastName = "Ratnam";
@observable initial = "K";
@computed get fullName() {
console.log("Computed");
return this.firstName + " " + this.lastName + " " + this.initial;
}
@action
changeFirstNameAndLastName = () => {
this.firstName = "Mark";
this.lastName = "Wayne";
this.initial = "J";
};
}
const newPerson = new Person();
// Reaction: log the profile info whenever it changes
// Example React component that observes state
const ProfileView = observer(props => {
console.log("render ProfileView");
return (
<div>
<p>{props.person.fullName}</p>
<button onClick={props.person.changeFirstNameAndLastName}>
Change first name and last name
</button>
</div>
);
});
render(<ProfileView person={newPerson} />, document.getElementById("root"));
When user presses
Change first name and last namebutton then due to batching the computed, ProfileView render fn should be triggered once, which is as expectedWhen we remove @action to the
changeFirstNameAndLastNamehandler as react might still batch the state updates, hence the computed fn should be triggered once and render fn should be called once
Instead computed fn is being logged twice.
- Check
Case 2snippet for the same.
Case 2: When react event handler is not wrapped with action
import React, { Component } from "react";
import { render } from "react-dom";
import { observable, action, computed, autorun } from "mobx";
import { observer } from "mobx-react";
class Person {
@observable firstName = "Ramu";
@observable lastName = "Ratnam";
@observable initial = "K";
@computed get fullName() {
console.log("Computed");
return this.firstName + " " + this.lastName + " " + this.initial;
}
changeFirstNameAndLastName = () => {
this.firstName = "Mark";
this.lastName = "Wayne";
this.initial = "J";
};
}
const newPerson = new Person();
// Reaction: log the profile info whenever it changes
// Example React component that observes state
const ProfileView = observer(props => {
console.log("render ProfileView");
return (
<div>
<p>{props.person.fullName}</p>
<button onClick={props.person.changeFirstNameAndLastName}>
Change first name and last name
</button>
</div>
);
});
render(<ProfileView person={newPerson} />, document.getElementById("root"));
Note:
If react batches the state updates inside changeFirstNameAndLastName, then computed fn should be logged once.
If react does not batches the state updates inside changeFirstNameAndLastName, then computed fn should be logged thrice.
Why computed fn is being logged twice instead?