Reputation: 399
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
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
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