Калькулятор ИМТ, написанный в классе react.js, необходимо дважды щелкнуть на кнопке отправки, чтобы изменить некоторые значения this.state.

Я работал над калькулятором BMI, написанным в компоненте класса response.js, я обнаружил, что нажатие кнопки отправки не изменяет некоторые значения this.state в первый раз, но второй щелчок изменит все значения, Я прочитал соответствующие вопросы по этим ссылкам:

Передавать значения дочернему компоненту при нажатии кнопки «Отправить» кнопка - ReactJS, нажмите дважды

ReactJS - нужно дважды щелкнуть, чтобы установить состояние и функция запуска

но я не мог понять, как внести изменения в свой код. Вот мой код:

import React, {Component} from 'react';
class App extends Component{
    constructor(props){
        super(props);
        this.state = {fullName: '', weight: '', height: '', bmi: '', message: '', optimalWeight: ''};
        this.handleChange = this.handleChange.bind(this);
        this.calculateBMI = this.calculateBMI.bind(this);
        this.handleSubmit =this.handleSubmit.bind(this);
    }

handleChange(e){
    this.setState({[e.target.name]: e.target.value});
}

calculateBMI(){
    let heightSquared = (this.state.height/100 * this.state.height/100);
    let bmi = this.state.weight / heightSquared;
    let low = Math.round(18.5 * heightSquared);
    let high = Math.round(24.99 * heightSquared);
    let message = "";
    if(bmi >= 18.5 && bmi <= 24.99){
        message = "You are in a healthy weight range";
    }
    else if(bmi >= 25 && bmi <= 29.9){
        message = "You are overweight";
    }
    else if(bmi >= 30){
        message="You are obese";
    }
    else if(bmi < 18.5){
        message="You are under weight";
    }
    this.setState({message: message});
    this.setState({optimalWeight: "Your suggested weight range is between "+low+ " - "+high});
    this.setState({bmi: Math.round(bmi * 100) / 100});
}


handleSubmit(e){
    this.calculateBMI();
    e.preventDefault();
    console.log(this.state);

}

    render(){
        return(
            <div className="App">
                <div className="App-header">
                    <h2>BMI calculator</h2>
                </div>
                <form onSubmit={this.handleSubmit}>
                    <label>
                        Please enter your name
                    </label>
                    <input type="text" name="fullName" value={this.state.fullName} onChange={this.handleChange} />
                    <label>
                        Enter your height in cm
                    </label>
                    <input type="number" name="height" value={this.state.height} onChange={this.handleChange} />
                    <label>
                        Enter your weight in kg
                    </label>
                    <input type="number" name="weight" value={this.state.weight} onChange={this.handleChange} />
                    <input type="submit" value="Submit"/>
                </form>
            </div>
        );
    }
}

export default App;

Обновить:

Я также проверяю вопрос Использование async setState, но моя проблема заключается не в обновлении асинхронным способом, а благодаря @LMulvey, я решил это, сгруппировав setState и добавив к нему console.log в качестве функции обратного вызова в calculateBMI ()


person Jordan Picaso    schedule 10.04.2019    source источник
comment
Вы можете установить все необходимые свойства состояния за один setState вызов.   -  person Emile Bergeron    schedule 10.04.2019
comment
Кроме того, setState является асинхронным, что объясняет, почему ваш журнал консоли не обновлен.   -  person Emile Bergeron    schedule 10.04.2019
comment
Возможный дубликат с использованием async setState   -  person Emile Bergeron    schedule 10.04.2019
comment
@EmileBergeron Я сгруппировал setState в calculateBMI (), но основное решение моей проблемы - добавить console.log в последний setState в calculateBMI (), как @ LMulvey ответил ниже   -  person Jordan Picaso    schedule 10.04.2019
comment
Мой первый комментарий был просто советом по обзору кода. Решение было во втором комментарии, ответ на который уже дан в моем третьем комментарии.   -  person Emile Bergeron    schedule 10.04.2019
comment
Глядя на вашу правку, похоже, вы упустили суть дублирующего кандидата. Даже если вы не хотите обновлять, setState по-прежнему является асинхронным, а решение обратного вызова описано в Использование async setState - та же концепция, которая нужна здесь. Это частая ошибка React.   -  person Emile Bergeron    schedule 10.04.2019
comment
@EmileBergeron Я видел ваш третий комментарий, но не смог решить свою проблему с помощью этого в stackoverflow .com / questions / 43370176 / using-async-setstate, с другой стороны, мой код представляет собой простой компонент класса реакции и не использует redux   -  person Jordan Picaso    schedule 10.04.2019
comment
В то время как другой спрашивающий использует функцию действия redux вместо console.log, проблема и решение те же ...   -  person Emile Bergeron    schedule 10.04.2019


Ответы (1)


Ваше приложение на самом деле работает нормально. Проблема в том, что вы пытаетесь зарегистрировать свое состояние до того, как setState будет полностью завершен. Если вместо этого вы прикрепите свой console.log в качестве обратного вызова к своему последнему вызову setState, вы увидите, что он работает так, как задумано.

this.setState({bmi: Math.round(bmi * 100) / 100}, () => console.log(this.state));

Стоит отметить, что вам не нужен один setState вызов для каждого свойства, которое вы обновляете, и вы можете сгруппировать их вместе следующим образом, что также может привести к вашей проблеме с условиями гонки здесь:

 this.setState({
    bmi: Math.round(bmi * 100) / 100,
    optimalWeight: "Your suggested weight range is between "+low+ " - "+high,
    message
}, () => console.log(this.state));
person LMulvey    schedule 10.04.2019
comment
спасибо, группировка setState и присоединение console.log в качестве обратного вызова к финальному setState - отличная идея, и она отлично работает - person Jordan Picaso; 10.04.2019