Why does computed is being logged two times instead of once?

Viewed 393
  • 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 name button then due to batching the computed, ProfileView render fn should be triggered once, which is as expected

  • When we remove @action to the changeFirstNameAndLastName handler 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 2 snippet 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?

0 Answers
Related