S
S
Sergey2019-07-20 22:56:07
React
Sergey, 2019-07-20 22:56:07

Why does the class method not pick up the necessary data in states if you call it from the constructor?

I have a component with a constructor that looks like this:

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

    this.caloriesCalculate();
  }

There is a caloriesCalculate() method. It looks like this:
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);
  }

The method works correctly when I bind it to a button click: But if it's called from a constructor, states still have values ​​of zero. At the same time, if you do console.log(nutritions);, then in the console it shows the correct values, but the data inside render() is zero. In render() this is what:
onClick={() => this.caloriesCalculate()}
<li className='day-calories'><b>Calories:</b> {calories}, <b>Fat:</b> {fat}g, <b>Protein:</b> {protein}g, <b>Carbs:</b> {carbs}g</li>

Passing values ​​to the constructor from the component's props is doing the same calculations in the parent component.
You can also do the calculations in the constructor - but then I still use the same code twice ( onClick={() => this.caloriesCalculate()} not for debugging and tests, but the desired method, i.e. just transfer all calculations to the constructor is not an option).
What am I doing wrong?
Why does this.calculateCalories() not pick up the necessary data in states from the constructor?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Anton Spirin, 2019-07-21
@butteff

In calculateCalories, instead of calling setState, you should return the computed state:

class Day extends React.Component {
  state = this.calculateCalories();

  calculateCalories() {
    /* ... */
    return {
      calories,
      fat,
      protein,
      carbs,
    };
  }

  handleClick = () => {
    this.setState(this.calculateCalories());
  };
  
  render() {
    ...
  }
}

Read more about the static method getDerivedStateFromProps . Might fit.
Well, if a state change is not implied, then there is not much point in writing data there, they can be used directly from props.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question