简体   繁体   中英

Why does the component is not re-rendering when i add @action decorator to an react event handler function

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.

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>
    );
  }
}

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM