David
David

Reputation: 173

State not updating immediately

I'm building a web app that calculates BMR by asking the user for age, weight, gender, feet, inches. After the user submits the form, there should be an alert box with the state of all objects. The only problem is, BMR is the only one that stays at 0; it doesn't update until I click submit again. I am working with two Classes: Macros(main) and Form. My code is below

class Macros extends React.Component{

constructor(props){
    super(props);

    this.state = {
        age: '',
        weight: '',
        male: true,
        feet: '',
        inches: '',
        BMR: 0,
    };

    this.handleAgeChange = this.handleAgeChange.bind(this);
    this.handleWeightChange = this.handleWeightChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleGenderChange = this.handleGenderChange.bind(this);
    this.handleFeetChange = this.handleFeetChange.bind(this);
    this.handleInchChange = this.handleInchChange.bind(this);
    this.calculateBMR = this.calculateBMR.bind(this);
}

handleAgeChange(event) {
    this.setState({age: event.target.value});
}

handleWeightChange(event) {
    this.setState({weight: event.target.value});
}

handleSubmit(event) {
    this.calculateBMR();
    event.preventDefault();
    alert('Age: ' + this.state.age + ' Weight: ' + this.state.weight + ' Male: ' + this.state.male 
    + ' Feet: ' + this.state.feet + ' Inches: ' + this.state.inches + ' BMR: ' + this.state.BMR) 
}

handleGenderChange(event) {
    this.setState({male: !this.state.male});
}

handleFeetChange(event) {
    this.setState({feet: event.target.value});
}

handleInchChange(event) {
    this.setState({inches: event.target.value});
}

calculateBMR() {
    let calBMR = 0;
    if(this.state.male){
        calBMR = ((10 * ((this.state.weight) / 2.20462)) + 
            (6.25 * ((this.state.feet * 30.48) + (this.state.inches * 2.54))) - 
            (5 * this.state.age)) + 5;
    }
    else {
        calBMR = ((10 * ((this.state.weight) / 2.20462)) + 
            (6.25 * ((this.state.feet * 30.48) + (this.state.inches * 2.54))) - 
            (5 * this.state.age)) - 161;
    }
    this.setState({BMR: calBMR});
}


render(){
    const title = 'Macro Apps';
    const subtitle = 'Calculate Your Macro-Nutrient Intake for Flexible Dieting';
    return (
        <div>
            <Header title={title} subtitle={subtitle} />
            <Form onAgeChange={this.handleAgeChange} onWeightChange={this.handleWeightChange}
                  onGenderChange={this.handleGenderChange} onFeetChange={this.handleFeetChange}
                  onInchChange={this.handleInchChange} onSubmit={this.handleSubmit}
            />
        </div>
    );
}
}

ReactDOM.render(<Macros />, document.getElementById('root'));

Form Class

import React from 'react';

export class Form extends React.Component{
    render(){
        return (
            <div>
                <form onSubmit={this.props.onSubmit}>
                    Age:
                    <input type="text" onChange={this.props.onAgeChange}/><br />
                    Weight:
                    <input type="text" onChange={this.props.onWeightChange} /><br />
                    <label>
                    <input 
                        type="radio"
                        name="gender"
                        checked="checked"
                        onChange={this.props.onGenderChange}
                    />
                    Male
                </label>
                <label>
                    <input 
                        type="radio"
                        name="gender"
                        onChange={this.props.onGenderChange}
                    />
                    Female<br/>
                </label>
                <input type="text" onChange={this.props.onFeetChange}/>ft 
                <input type="text" onChange={this.props.onInchChange}/>in<br/>
                <input type="submit" value="Submit" />
            </form>
        </div>
    )
}
}

Upvotes: 1

Views: 132

Answers (2)

孟林伦
孟林伦

Reputation: 21

you can change like below or try to use Mobx

`class Macros extends React.Component{
constructor(props){
    super(props);
    this.state = {
        age: '',
        weight: '',
        male: true,
        feet: '',
        inches: '',
        BMR: 0,
    };

    this.handleAgeChange = this.handleAgeChange.bind(this);
    this.handleWeightChange = this.handleWeightChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleGenderChange = this.handleGenderChange.bind(this);
    this.handleFeetChange = this.handleFeetChange.bind(this);
    this.handleInchChange = this.handleInchChange.bind(this);
    this.calculateBMR = this.calculateBMR.bind(this);
}

handleAgeChange(event) {
    this.setState({age: event.target.value},this.calculateBMR);
}

handleWeightChange(event) {
    this.setState({weight: event.target.value},this.calculateBMR);
}

handleSubmit(event) {

    event.preventDefault();
    alert('Age: ' + this.state.age + ' Weight: ' + this.state.weight + ' Male: ' + this.state.male 
    + ' Feet: ' + this.state.feet + ' Inches: ' + this.state.inches + ' BMR: ' + this.state.BMR) 
}

handleGenderChange(event) {
    this.setState({male: !this.state.male},this.calculateBMR);
}

handleFeetChange(event) {
    this.setState({feet: event.target.value},this.calculateBMR);
}

handleInchChange(event) {
    this.setState({inches: event.target.value},this.calculateBMR);
}

calculateBMR() {
    let calBMR = 0;
    if(this.state.male){
        calBMR = ((10 * ((this.state.weight) / 2.20462)) + 
            (6.25 * ((this.state.feet * 30.48) + (this.state.inches * 2.54))) - 
            (5 * this.state.age)) + 5;
    }
    else {
        calBMR = ((10 * ((this.state.weight) / 2.20462)) + 
            (6.25 * ((this.state.feet * 30.48) + (this.state.inches * 2.54))) - 
            (5 * this.state.age)) - 161;
    }
    this.setState({BMR: calBMR});
}


render(){
    const title = 'Macro Apps';
    const subtitle = 'Calculate Your Macro-Nutrient Intake for Flexible Dieting';
    return (
        <div>
            <Header title={title} subtitle={subtitle} />
            <Form onAgeChange={this.handleAgeChange} onWeightChange={this.handleWeightChange}
                  onGenderChange={this.handleGenderChange} onFeetChange={this.handleFeetChange}
                  onInchChange={this.handleInchChange} onSubmit={this.handleSubmit}
            />
        </div>
    );
}
}

ReactDOM.render(<Macros />, document.getElementById('root'));
`

Upvotes: 0

aprogrammer
aprogrammer

Reputation: 1774

In ReactJS setting state is asynchronous. You can simply pass a callback to setState method like this:

setState({ "something": "needs to change" }, () => { /* will be invoked when the state changes. */ })

So this lines of code:

handleSubmit(event) {
    this.calculateBMR();
    ...
}

calculateBMR() {
    ...
    this.setState({BMR: calBMR});
}

Could be look like this:

handleSubmit(event) {
    this.calculateBMR(() => {
         alert('Age: ' + this.state.age + ' Weight: ' + this.state.weight + ' Male: ' + this.state.male + 
         ' Feet: ' + this.state.feet + ' Inches: ' + this.state.inches + ' BMR: ' + this.state.BMR) 
    });
}

calculateBMR(callback) {
    this.setState({ BMR: calBMR }, callback);
}

Upvotes: 2

Related Questions