Understanding the BMI Calculator Code in React and Next.js

Published on 2024-12-20

In this blog post, we will break down a simple BMI (Body Mass Index) calculator built using React and Next.js. This application allows users to input their weight and height, select a unit system (metric or imperial), and calculate their BMI along with a corresponding category. Let’s dive into the code and understand each part in detail.


Setting Up the Component

'use client';
At the beginning of our code, we have the line 'use client';. This directive is essential in Next.js as it indicates that the component we are defining is a client component. This means that it can utilize React hooks and manage state, which is crucial for interactive applications like our BMI calculator. Following this, we import the useState hook from React.
import { useState } from 'react';
The useState hook is a fundamental part of React that allows us to create state variables within our functional component.Next, we define our functional component named Bmi. This component will encapsulate all the logic and UI elements necessary for our BMI calculator. By using a functional component, we can take advantage of React's modern features, such as hooks, which make our code cleaner and more efficient.
export default function Bmi() {


Managing State

Inside our Bmi component, we create several state variables using the useState hook. We initialize weight to 70, which represents the default weight in kilograms, and height to 180, representing the default height in centimeters. These initial values provide a starting point for our calculations. We also create a state variable called bmi, initialized to 0, which will hold the calculated BMI value once the user inputs their data.
const [weight, setWeight] = useState(70);
const [height, setHeight] = useState(180);
const [bmi, setBmi] = useState(0);
const [category, setCategory] = useState('');
const [unitSystem, setUnitSystem] = useState('metric');
Additionally, we have a category state variable, which starts as an empty string. This variable will be used to store the BMI category (such as Underweight, Normal, Overweight, or Obese) based on the calculated BMI. Lastly, we introduce a unitSystem state variable, initialized to 'metric'. This variable allows users to choose between metric and imperial units, making our application more versatile and user-friendly.


BMI Calculation Logic

The heart of our BMI calculator lies in the calculateBMI function. This function is triggered when the user clicks the "Calculate BMI" button. Inside this function, we first calculate the BMI using the formula weight / (height * height). This formula is valid for the metric system, where weight is measured in kilograms and height in meters.
const calculateBMI = () => {
  let calculatedBMI = weight / (height * height);
However, if the user selects the imperial unit system, we need to convert the input values to metric units before performing the calculation. We achieve this by converting weight from pounds to kilograms using the conversion factor (1 pound = 0.453592 kilograms) and height from inches to meters (1 inch = 0.0254 meters). After performing the necessary conversions, we apply the same BMI formula to calculate the BMI in metric units.
if (unitSystem === 'metric') {
  calculatedBMI = weight / (height * height);
} else {
  const weightKg = weight * 0.453592;
  const heightM = height * 0.0254;
  calculatedBMI = weightKg / (heightM * heightM);
}
Once we have the calculated BMI, we update the bmi state variable using setBmi, rounding the value to one decimal place for better readability.
setBmi(parseFloat(calculatedBMI.toFixed(1)));
Following this, we categorize the BMI value into one of four categories: Underweight, Normal, Overweight, or Obese. This categorization is done using a series of conditional statements that check the calculated BMI against standard thresholds. By updating the category state variable accordingly, we provide users with immediate feedback on their BMI status.
if (calculatedBMI < 18.5) {
  setCategory('Underweight');
} else if (calculatedBMI < 25) {
  setCategory('Normal');
} else if (calculatedBMI < 30) {
  setCategory('Overweight');
} else {
  setCategory('Obese');
}


Rendering the Component

The return statement of our Bmi component contains the JSX that defines the user interface of our BMI calculator. We start with a div that serves as a container for our application, styled with Tailwind CSS classes to ensure it is visually appealing and responsive. Inside this container, we include a heading (h1) that displays the title of our application, "BMI Calculator," prominently at the top.
return (
  <div className="container mx-auto p-4">
    <h1 className="text-2xl font-bold mb-4">BMI Calculator</h1>
Next, we create a dropdown menu that allows users to select their preferred unit system. This dropdown is implemented using a select element, which is populated with two options: Metric (kg/m²) and Imperial (lb/in²). The value of the dropdown is bound to the unitSystem state variable, and we use the onChange event to update this state whenever the user makes a selection. This dynamic behavior ensures that the application responds to user input in real-time.
<select value={unitSystem} onChange={(e) => setUnitSystem(e.target.value)}>
  <option value="metric">Metric (kg/m²)</option>
  <option value="imperial">Imperial (lb/in²)</option>
</select>
Following the unit system selector, we have input fields for weight and height. The labels for these fields change based on the selected unit system, providing a clear indication of what the user should enter. The input fields are controlled components, meaning their values are tied to the corresponding state variables (weight and height). When the user types in these fields, the onChange event updates the state with the new values, ensuring that our calculations are always based on the most current input.
<label>
  {unitSystem === 'metric' ? 'Weight (kg)' : 'Weight (lb)'}
  <input
    type="number"
    value={weight}
    onChange={(e) => setWeight(e.target.value)}
    className="border p-2"
  />
</label>
<label>
  {unitSystem === 'metric' ? 'Height (cm)' : 'Height (in)'}
  <input
    type="number"
    value={height}
    onChange={(e) => setHeight(e.target.value)}
    className="border p-2"
  />
</label>
Finally, we include a button labeled "Calculate BMI." When clicked, this button triggers the calculateBMI function, performing the calculations and updating the displayed BMI and category. If the BMI is greater than 0, we display the calculated BMI and the corresponding category to the user.
<button onClick={calculateBMI} className="bg-blue-500 text-white p-2 mt-4">
  Calculate BMI
</button>
{bmi > 0 && (
  <div className="mt-4">
    <p>Your BMI is: {bmi}</p>
    <p>Category: {category}</p>
  </div>
)}
This structure not only makes the BMI calculator functional but also ensures that it is user-friendly and visually appealing. By following this breakdown, you can see how each part of the code contributes to the overall functionality of the application, allowing you to easily calculate and understand their BMI.


Complete Code Testing the Application

Here is the completed code
'use client';

import { useState } from 'react';

export default function Bmi() {
  const [weight, setWeight] = useState(70);
  const [height, setHeight] = useState(180);
  const [bmi, setBmi] = useState(0);
  const [category, setCategory] = useState('');
  const [unitSystem, setUnitSystem] = useState('metric');

  const calculateBMI = () => {
    let calculatedBMI = weight / (height * height);

    if (unitSystem === 'metric') {
      calculatedBMI = weight / (height * height);
    } else {
      // Convert imperial units to metric
      const weightKg = weight * 0.453592;
      const heightM = height * 0.0254;
      calculatedBMI = weightKg / (heightM * heightM);
    }

    setBmi(parseFloat(calculatedBMI.toFixed(1)));

    // Categorize BMI (you can customize categories as needed)
    if (calculatedBMI < 18.5) {
      setCategory('Underweight');
    } else if (calculatedBMI < 25) {
      setCategory('Normal');
    } else if (calculatedBMI < 30) {
      setCategory('Overweight');
    } else {
      setCategory('Obese');
    }
  };

  return (
    <div className="container mx-auto p-4 bg-gray-800 text-white rounded">
      <h1 className="text-3xl font-bold text-center mb-4">BMI Calculator</h1>
      <div className="flex flex-col items-center">
        <div className="mb-4">
          <label className="block text-sm font-medium text-white">
            Unit System
          </label>
          <select
            className="border border-gray-300 text-black p-2 rounded"
            value={unitSystem}
            onChange={(e) => setUnitSystem(e.target.value)}
          >
            <option value="metric">Metric (kg/m²)</option>
            <option value="imperial">Imperial (lb/in²)</option>
          </select>
        </div>
        <div className="mb-4 flex flex-col">
          <label htmlFor="weight" className="text-sm font-medium mb-1">
            {unitSystem === 'metric' ? 'Weight (kg)' : 'Weight (lbs)'}
          </label>
          <input
            type="number"
            id="weight"
            className="border border-gray-300 p-2 rounded text-black"
            value={weight}
            onChange={(e) => setWeight(parseFloat(e.target.value))}
          />
        </div>
        <div className="mb-4 flex flex-col">
          <label htmlFor="height" className="text-sm font-medium mb-1">
            {unitSystem === 'metric' ? 'Height (m)' : 'Height (in)'}
          </label>
          <input
            type="number"
            id="height"
            className="border border-gray-300 p-2 rounded text-black"
            value={height}
            onChange={(e) => setHeight(parseFloat(e.target.value))}
          />
        </div>
        <button
          className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
          onClick={calculateBMI}
        >
          Calculate BMI
        </button>
        {bmi > 0 && (
          <div className="mt-4">
            <p className="text-xl font-bold">Your BMI is: {bmi}</p>
            <p className="text-lg">Category: {category}</p>
          </div>
        )}
      </div>
    </div>
  );
}
Now that we have everything in place, let's run the application. In your terminal, use the following command:
npm run dev
Open your browser and navigate to http://localhost:3000. Enter your birth date and click the "Calculate Age" button. You should see your age displayed on the screen!


Conclusion

In conclusion, we have built a functional BMI calculator using React and Next.js that allows users to input their weight and height, select their preferred unit system, and calculate their BMI along with a corresponding category. By breaking down the code, we have seen how each part contributes to the overall functionality of the application. From managing state with the useState hook to implementing the BMI calculation logic and rendering a user-friendly interface, every aspect plays a crucial role in creating an interactive experience.
You can see the BMI calculator in action by clicking the link below:
This project not only demonstrates the power of React and Next.js but also serves as a practical example of how to build a simple yet effective web application. Whether you are a beginner or an experienced developer, understanding this code can help you enhance your skills and apply similar concepts in your future projects.