Reputation: 567
I have a page where I update two fields and successfully get the state variables updated, to a point. The last update reflects in the render part, but can not pass beyond that. What am I doing wrong? Am I missing something? Suggestions?
When typing to the height field the corresponding state is updated, same goes for the weight field, and rendering this is ok. But when I try to make the calculation, I can not do so accurately since I am missing the last update on any one of the mentioned fields.
// index.jsx
import React from "react";
import ReactDOM from "react-dom";
class BmiReactForm extends React.Component {
constructor(props) {
super(props);
this.state = {
height: 0,
weight: 0,
factor: 'Unknown',
category: 'Undefined'
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(input, value) {
this.setState({[input]: value});
const height = parseFloat(this.state.height).toFixed(2);
const weight = parseFloat(this.state.weight).toFixed(2);
this.bmiCalc(height, weight);
}
bmiCalc(height, weight) {
if ((height > 0) && (weight > 0)) {
let bmiNumber = weight/(height * height);
let bmiString = 'Undefined'
switch(true) {
case (bmiNumber < 15):
bmiString = 'Very severely underweight';
break;
case (bmiNumber >= 15 && bmiNumber < 16):
bmiString = 'Severely underweight';
break;
case (bmiNumber >= 16 && bmiNumber < 18.5):
bmiString = 'Underweight';
break;
case (bmiNumber >= 18.5 && bmiNumber < 25):
bmiString = 'Normal (healthy weight)';
break;
case (bmiNumber >= 25 && bmiNumber < 30):
bmiString = 'Overweight';
break;
case (bmiNumber >= 30 && bmiNumber < 35):
bmiString = 'Obese Class I (Moderately obese)';
break;
case (bmiNumber >= 35 && bmiNumber < 40):
bmiString = 'Obese Class II (Severely obese)';
break;
case (bmiNumber >= 40):
bmiString = 'Obese Class III (Very severely obese)';
break;
}
this.setState({factor: bmiNumber});
this.setState({category: bmiString});
} else {
this.setState({factor: 'Unknown'});
this.setState({category: 'Undefined'});
}
}
render() {
const factor = this.state.factor;
const category = this.state.category;
return (
<div>
<form>
<input id="csrf_token" name="csrf_token" type="hidden" value="IjFhOWU1NTg2OWFiYTA0NTMzYjhhMDM5YWRhOGNjOThhMTk1MDJiNjEi.DYtlyQ.k8gVqs8uX9TLTOrnTF3aeOJXjoY" />
<p>
<label>Height</label> <input class="form-control"
id="height" type="text"
name="height"
placeholder={this.state.height}
onChange={e => this.handleChange('height', e.target.value)} />
</p>
<p>
<label>Weight</label> <input class="form-control"
id="weight" type="text"
name="weight"
placeholder={this.state.weight}
onChange={e => this.handleChange('weight', e.target.value)} />
</p>
<div class="jumbotron">
<p>
<label>Factor:</label> <span>{factor}</span>
</p>
<p>
<label>Category:</label> <span>{category}</span>
</p>
</div>
</form>
</div>
);
}
}
ReactDOM.render(<BmiReactForm />, document.getElementById("BmiReactForm"));
What is needed to guarantee the calculation will always take into account the latest update?
Thanks for your time and effort.
Upvotes: 0
Views: 48
Reputation: 18
Use this.setState( ( prevState, props ) => ({}) )
method at the place of this.setState({})
. Because it's not ensuring that the you are getting a new updated state every time.
Upvotes: 0
Reputation: 927
call this.bmiCalc
in the callback to setState
e.g.
this.setState({[ input ]}: value }, () => {
const height = parseFloat(this.state.height).toFixed(2);
const weight = parseFloat(this.state.weight).toFixed(2);
this.bmiCalc(height, weight);
});
This ensures that the state transition occurs BEFORE you attempt a calculation.
If you're not using ES6 (you are, but just in case anyway)
this.setState({[ input ]}: value }, function() {
const height = parseFloat(this.state.height).toFixed(2);
const weight = parseFloat(this.state.weight).toFixed(2);
this.bmiCalc(height, weight);
});
Upvotes: 1