0

I am Trying to make a Simple React BMI Calculator. I am trying to implement something like when ı click the submit button i want to create new html at the bottom like

your body index is {yourindex}

everytime that i click the submit button. You can think same like in todo apps.

How can ı do that ? Thanks

import React, { Component } from 'react'

class Areas extends Component {
  constructor(props) {
    super(props)
  
    this.state = {
       kg:0,
       height:0,
    }
    this.updateKG = this.updateKG.bind(this)
    this.updateHeight = this.updateHeight.bind(this)
    this.calculateBMI = this.calculateBMI.bind(this)
  }

  updateKG(event){
    this.setState({kg:event.target.value})
  }
  
  updateHeight(event){
    this.setState({height:event.target.value})
  }

  calculateBMI(){
    this.state.totals.push(parseInt(this.state.kg) + parseInt(this.state.height))
    console.log(this.state.totals)
  }
  
  
  render() {
    return (
      <div>

        <div className="jumbotron text-center mt-3">
          <div className="container">
            <h1 className="display-4">Calculate Your BMI</h1>
            <p className="lead">Calculate How fat you are ?</p>
          </div>
        </div>
        

        <div className="container mt-5">
          <div className="row">
            
            <div className="col text-center">
              <p>Your Kg</p>
              <input type="number" min="30" onChange={this.updateKG}/>
            </div>
            
            <div className="col text-center">
              <p>Your Height in cm</p>
              <input type="number" min="60" onChange={this.updateHeight}/>
            </div>
            
            <div className="col text-center">
              <p>Calculate Your BMI</p>
              <button className="btn btn-success" type="submit" onClick={this.calculateBMI}>Submit</button>
            </div>
            
          </div>
        </div>
      </div>
    )
  }
}

export default Areas
2
  • 1
    You would generally store submitted data as a state and display a div or component based on the state. I personally prefer display portion to be a separate component but it's a design decision and irrelevant to code. Commented Sep 10, 2021 at 12:30
  • 1
    By state, I mean array of {kg: value, height: value}. Commented Sep 10, 2021 at 12:33

4 Answers 4

1

I've updated the snippet to show the calculations.

You were almost right but you were updating totals without this.setState function.

then in render method you can just iterate over totals and thats it.

You updated snippet is here.

class Areas extends Component<any, any> {
  state = {
    kg: 0,
    height: 0,
    totals: [],
  };

  updateKG = (event: any) => {
    this.setState({ kg: parseInt(event.target.value) });
  };

  updateHeight = (event: any) => {
    this.setState({ height: parseInt(event.target.value) });
  };

  calculateBMI = () => {
    // formula https://www.cdc.gov/nccdphp/dnpao/growthcharts/training/bmiage/page5_1.html

    const bmi = Math.round(
      (this.state.kg / this.state.height / this.state.height) * 10000,
    );

    console.log(bmi);

    this.setState({
      totals: [...this.state.totals, bmi],
    });
  };

  render() {
    return (
      <div>
        <div className="jumbotron text-center mt-3">
          <div className="container">
            <h1 className="display-4">Calculate Your BMI</h1>
            <p className="lead">Calculate How fat you are ?</p>
          </div>
        </div>

        <div className="container mt-5">
          <div className="row">
            <div className="col text-center">
              <p>Your Kg</p>
              <input type="number" min="30" onChange={this.updateKG} />
            </div>

            <div className="col text-center">
              <p>Your Height in cm</p>
              <input type="number" min="60" onChange={this.updateHeight} />
            </div>

            <div className="col text-center">
              <p>Calculate Your BMI</p>
              <button
                className="btn btn-success"
                type="submit"
                onClick={this.calculateBMI}
              >
                Submit
              </button>
            </div>
          </div>
          {this.state.totals.map((total: any, i: number) => {
            return <div key={i}>Calculated BMI: {total}</div>;
          })}
        </div>
      </div>
    );
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

thanks for the code it works but ı have question what this event: any does ? also totals: [...this.state.totals, bmi], does ?
@tallcoder It does nothing if you are using plain Javascript. In order to quick edit your snippet I've pasted code into my editor where I use Typescript. And for Typescript it means annotation of variable type. If you're interested check out this typescriptlang.org/docs/handbook/2/everyday-types.html
And in case of [...this.state.totals, bmi]. This is basically adding item to array with method called spread operator. You can also learn more here: javascripttutorial.net/es6/javascript-spread
1

From your code, you can add another component or code. Here is the steps on how you can make them.

  1. create a variable to show the result. First set it to "false" because we want to hide it.

  2. create another code to display user BMI result

  3. use that variable to show the result. For example, {showResult ? Something if true : something if false}. You have to use ternary operator to show or hide the user result

  4. Inside the calculated Bmi function, use "setState" to change the variable to "true"

That is all the step that you have to do. Hope this help

Comments

1

You can collect your totals in an array in your state and render elements based on that:

class Areas extends Component {
  constructor(props) {
    super(props)
  
    this.state = {
       kg:0,
       height:0,
       totals: []
    }
    this.updateKG = this.updateKG.bind(this)
    this.updateHeight = this.updateHeight.bind(this)
    this.calculateBMI = this.calculateBMI.bind(this)
  }

  updateKG(event){
    this.setState({kg:event.target.value})
  }
  
  updateHeight(event){
    this.setState({height:event.target.value})
  }

  calculateBMI(){
    // This just adds weight and height, but you can replace it with the actual calculation
    const total = parseInt(this.state.kg) + parseInt(this.state.height)
    this.setState({totals: this.state.totals.concat([total])});
    console.log(this.state.totals)
  }
  
  render() {
    return (
      <div>

        <div className="jumbotron text-center mt-3">
          <div className="container">
            <h1 className="display-4">Calculate Your BMI</h1>
            <p className="lead">Calculate How fat you are ?</p>
          </div>
        </div>
        

        <div className="container mt-5">
          <div className="row">
            
            <div className="col text-center">
              <p>Your Kg</p>
              <input type="number" min="30" onChange={this.updateKG}/>
            </div>
            
            <div className="col text-center">
              <p>Your Height in cm</p>
              <input type="number" min="60" onChange={this.updateHeight}/>
            </div>
            
            <div className="col text-center">
              <p>Calculate Your BMI</p>
              <button className="btn btn-success" type="submit" onClick={this.calculateBMI}>Submit</button>
            </div>

            {
                // Renders one element for each element in totals
                this.state.totals.map(total => <p>Your BMI is {total}</p>)
            }
            
          </div>
        </div>
      </div>
    )
  }
}

Comments

1

I can see Multiple problems with your code apart from your wrong BMI formula.

  1. When you set state, you are replacing old state with a new state. In your case since you are not considering old state while setState, you are losing either height or weight in this process.

You had to set state like this.setState({…this.state, height: e.target.value}) same for weight.

  1. Type of your button is Submit but there’s no form. You may remove that.

  2. You don’t have a property total or name it bmi in your state to hold the calculated bmi

  3. In your calculations you have a total assumed to be an array and used push array method. Push will mutate the data and we have avoid those methods which will mutate data in react. Use spread operator instead.

[…oldArray, newValue] this will produce new array. You are safe to use array methods like map, filter, and reduce etc as they all return a new array and not mutate the array.

  1. You are not displaying the calculated BMI anywhere.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.