1

Problem:

The below react component is not re-rendering when I add @action decorator to the class member fn.

import { observable, action } from "mobx";
import { observer } from "mobx-react";
import * as React from "react";
import { render } from "react-dom";

@observer
class PriceCounter extends React.Component {
  @observable price = 0;

  @action
  setPrice = () => {
    this.price = this.price + 1;
  };

  @action
  currentPrice = () => {
    return this.price;
  }

  render() {
    return (
      <div>
        <span className="text-3xl">Total: {this.currentPrice()}</span>
        <button onClick={this.setPrice}>Change details</button>
      </div>
    );
  }
}

render(<PriceCounter />, document.getElementById("root"));

  • The PriceCounter component re-renders as expected when @action is removed from currentPrice fn.

Why? Explanation needed.

Pavan Gangireddy
  • 417
  • 1
  • 3
  • 13

3 Answers3

1

Either you can use this.price to show the updated value of price. Or you can use computed decorator to do this.

@observer
class PriceCounter extends React.Component {
  @observable price = 0;

  @action
  setPrice = () => {
    this.price = this.price + 1;
  };

  @computed
  get currentPrice() {
    return this.price;
  }

  render() {
    return (
      <div>
        <span className="text-3xl">Total: {this.currentPrice}</span>
        <button onClick={this.setPrice}>Change details</button>
      </div>
    );
  }
}

or

@observer
class PriceCounter extends React.Component {
  @observable price = 0;

  @action
  setPrice = () => {
    this.price = this.price + 1;
  };

  @action
  currentPrice = () => {
    return this.price;
  };

  render() {
    return (
      <div>
        <span className="text-3xl">Total: {this.price}</span>
        <button onClick={this.setPrice}>Change details</button>
      </div>
    );
  }
}
chandan_kr_jha
  • 557
  • 4
  • 12
  • As you correctly pointed out, I understood that the right thing to do is to use computed for the currentPrice fn. However, I want to know why `@action` is blocking the re-render? Why the react component behavior is being affected when we add `@action` decorator to a class member fn? – Pavan Gangireddy May 11 '20 at 04:16
  • Refer this https://mobx.js.org/refguide/action.html . From source: It is advised to use (@)action on any function that modifies observables or has side effects. action also provides useful debugging information in combination with the devtools. – chandan_kr_jha May 11 '20 at 05:21
1

This is a wrong usage of action.

@action is expected to be wrapped around a function in which observables are changed. Here, you are not changing any observables in currentPrice function.

Since render is a tracked function in mobx-react, if you are not wrapping currentPrice function with action & if you call this.currentPrice() mobx tracks observables used in that function.

If you are wrapping functions used in a tracked function with action mobx doesn't know if you intend to track observables or do you want to run tracked functions after the function is executed.

Chinmaya
  • 11
  • 1
1

Actions should only, and always, be used on functions that modify state. Have a look at When to use actions

In the example you mentioned, currentPrice method is not modifying the state. So you need not use action decorator to that.

Prasanth
  • 26
  • 1