How to update states in a constructor with another method of the same class?

I have a component with a constructor:

<code lang="javascript">
class Day extends Component {
  constructor(props) {
    super(props);
    this.state = {
      calories: 0,
      fat: 0,
      protein: 0,
      carbs: 0,
    };

    this.caloriesCalculate();
  }
</code>

I have a method caloriesCalculate(). It has this code:

<code lang="javascript">
caloriesCalculate() {

    var fat = 0;
    var protein = 0;
    var carbs = 0;
    var calories = 0;

    const { dataArray, mealPlan, date } = this.props;
    const { products } = dataArray;

    var timestamp = date._i/1000;
    Object.keys(mealPlan[timestamp]).map(function(type) {
      var product = products[mealPlan[timestamp][type]];
      fat += product.fat/1000;
      protein += product.protein/1000;
      carbs += product.carb/1000;
      calories += product.calories/1000;
    });

    var nutritions = {
      calories: calories,
      fat: fat,
      protein: protein,
      carbs: carbs,
    }

    this.setState(nutritions);
  }
</code>

The method works well, when I assign it to a button click:

<code lang="javascript">
onClick={() => this.caloriesCalculate()}
</code>

But if the method is executed from the constructor, the states have zero values. In the same time, if I do console.log(nutritions);, it shows valid values in the console, but inside the render() - zero values.

In render() I have this:

<code lang="javascript">
<li className='day-calories'><b>Calories:</b> {calories}, <b>Fat:</b> {fat}g, <b>Protein:</b> {protein}g, <b>Carbs:</b> {carbs}g</li>
</code>

If I will have values in the constructor from props of a parent component - it is about to have the same calculation but inside the parent component.

I can do the calculation in the constructor - but it is about a double calculation too ( onClick={() => this.caloriesCalculate()} - it is not for a test or for a debug, I use this button with this method).

What am I doing wrong? Why this.calculateCalories() doesn't take in states valid data from the constructor?

Upvotes: 0

Views: 478

Answers (2)

Dennis Vash
Dennis Vash

Reputation: 53994

You using setState - which is async within the constructor, try moving the function call to another life cycle like componendDidMount

class Day extends Component {
  state = {
    calories: 0
    ...
  };

  componendDidMount = () => {
    this.caloriesCalculate();
  };

  caloriesCalculate = () => {
    // ... set nutritions
    this.setState(nutritions);
  };
}

Side Note: Avoid using var write more concise code.

Upvotes: 2

fastblast
fastblast

Reputation: 13

The constructor of a react component is called only once and before the DOM is mounted. Also, you should not call setState in the constructor. So first, the constructor is called and then the render method. In other words, you are calling this.caloriesCalculate(); in the constructor, before the list is shown on the screen. To solve your issue, you need to use React life cycle hooks. The one you need is componentDidMount()

constructor(props) {
  super(props);
  this.state = {
    calories: 0,
    fat: 0,
    protein: 0,
    carbs: 0,
  };
 }

  componentDidMount() {
    this.caloriesCalculate();
  }

  caloriesCalculate() {
    // your code.
  }

You can read more about the life cycle hooks here.

Upvotes: 1

Related Questions