Mobile phone displaying a React BMI calculator app with height and weight input sliders and BMI result of 23.5 indicating healthy range

Technical Blog Article — App 35: BMI Calculator with React, TypeScript, Vite, and Fluent UI

Mobile phone displaying a React BMI calculator app with height and weight input sliders and BMI result of 23.5 indicating healthy range
A person uses a React BMI calculator app on a mobile phone to check their health category.

The BMI Calculator is one of the most important applications in the entire learning roadmap because it introduces one of the core principles of modern React:

Derived values should be calculated during rendering instead of duplicated in state.

This application belongs to Block 2 — Interactivity and State, where the roadmap focuses on:

  • useState
  • controlled inputs
  • forms
  • events
  • derived state
  • validations
  • dynamic rendering

The official project structure defines App 35 as:

35. Calculadora IMC / BMI Calculator

inside the interactivity block.

The application appears simple visually, but architecturally it introduces several extremely important React concepts:

  • component memory
  • controlled forms
  • derived calculations
  • render cycle
  • numeric conversion
  • TypeScript typing
  • separation of responsibilities
  • utility functions
  • enterprise UI composition

This app is also a perfect demonstration of React’s declarative philosophy.

Instead of manually updating HTML elements, React recalculates the interface automatically whenever state changes.


The Goal of the Application

The BMI Calculator allows the user to:

  • enter weight
  • enter height
  • calculate BMI automatically
  • see a classification dynamically
  • view enterprise Fluent UI styling

The application demonstrates that React UI is always derived from state.


Understanding BMI

BMI means:

Body Mass Index

The formula is:

BMI = \frac{weight}{height^2}

Where:

  • weight = kilograms
  • height = meters

Example:

BMI = \frac{80}{1.75^2}

The result determines categories such as:

BMIClassification
< 18.5Underweight
18.5–24.9Normal
25–29.9Overweight
≥ 30Obesity

Project Creation

PowerShell Commands

cd C:\ReactApps
mkdir bloco02
cd bloco02
npm create vite@latest app35-bmi-calculator -- --template react-ts
cd app35-bmi-calculator
npm install
npm install @fluentui/react-components @fluentui/react-icons

This creates a React + TypeScript project using Vite.


Why Vite Matters

Vite is the build tool responsible for:

  • development server
  • JSX transformation
  • TypeScript compilation
  • module resolution
  • Hot Module Replacement
  • production build optimization

The project roadmap standardizes all apps using:

  • React
  • TypeScript
  • Vite
  • Fluent UI

This standardization is defined in the project structure documents.


Creating the Folder Structure

PowerShell

mkdir src\components
mkdir src\models
mkdir src\utils
mkdir src\styles

Create files:

New-Item src\components\BmiCalculatorCard.tsx -ItemType File
New-Item src\models\BmiClassification.ts -ItemType File
New-Item src\utils\bmiUtils.ts -ItemType File
New-Item artigo.md -ItemType File

Final Project Structure

src/
components/
BmiCalculatorCard.tsx
models/
BmiClassification.ts
utils/
bmiUtils.ts
styles/
App.tsx
main.tsx
index.css

This structure follows the architectural standard defined in the project roadmap.


Understanding the Architecture

The application flow becomes:

main.tsx
App.tsx
BmiCalculatorCard.tsx
bmiUtils.ts

Each file has a specific responsibility.


The Role of main.tsx

The file:

src/main.tsx

is the React entry point.

import React from "react";
import ReactDOM from "react-dom/client";
import {
FluentProvider,
webLightTheme,
} from "@fluentui/react-components";
import App from "./App";
ReactDOM.createRoot(
document.getElementById("root")!
).render(
<React.StrictMode>
<FluentProvider theme={webLightTheme}>
<App />
</FluentProvider>
</React.StrictMode>
);

This file performs several critical tasks:

ResponsibilityPurpose
ReactDOM.createRoot()Mount React into HTML
StrictModeDetect unsafe patterns
FluentProviderActivate Microsoft design system
webLightThemeApply Fluent UI light theme
<App />Render root component

How React Enters the Browser

The browser first loads:

index.html

Inside it exists:

<div id="root"></div>

React finds this element:

document.getElementById("root")

Then React injects the entire application into that container.

Flow:

index.html
main.tsx
ReactDOM.createRoot()
<App />
Components
Rendered HTML

This is how React becomes visible inside the browser.


The Role of App.tsx

import { BmiCalculatorCard } from "./components/BmiCalculatorCard";
function App() {
return (
<main
style={{
minHeight: "100vh",
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#f3f2f1",
}}
>
<BmiCalculatorCard />
</main>
);
}
export default App;

This component is responsible for:

  • page layout
  • centering
  • viewport sizing
  • root composition

The component hierarchy becomes:

App
BmiCalculatorCard

The Role of BmiCalculatorCard.tsx

This is the main business component.

It contains:

  • state
  • inputs
  • calculations
  • rendering logic
  • visual composition

Understanding useState

The component contains:

const [weight, setWeight] = useState("80");
const [height, setHeight] = useState("1.75");

This is React state.

State means:

Persistent component memory between renders.

Breaking Down useState

const [weight, setWeight] = useState("80");

contains three parts:

PartMeaning
weightcurrent state value
setWeightupdate function
"80"initial state

When the user types:

85

React updates state automatically.


Controlled Inputs

The input field is:

<Input
value={weight}
onChange={(_, data) =>
setWeight(data.value)
}
/>

This is called a:

Controlled input

React fully controls the input value.

Flow:

User types
onChange fires
setWeight()
State changes
React re-renders
Input receives updated value

This is one of the most important React concepts.


Why Inputs Return Strings

HTML inputs always return strings.

Even numeric-looking values are strings:

"80"
"1.75"

That is why we convert:

Number(weight)
Number(height)

before calculations.


The Numeric Conversion

const weightValue = Number(weight);
const heightValue = Number(height);

Without this conversion:

"80" + "5"

would produce:

"805"

instead of:

85

Numeric conversion is essential in forms.


The Most Important Concept: Derived State

The BMI value is calculated like this:

const bmi = calculateBmi(
weightValue,
heightValue
);

Notice something important:

BMI is NOT stored in state.

This is extremely important.

Wrong approach:

const [bmi, setBmi] = useState(0);

Correct approach:

const bmi = calculateBmi(...);

Why?

Because BMI can always be derived from:

  • weight
  • height

According to React Learn:

  • duplicated state creates bugs
  • derived values should be calculated

This follows:


Why No useEffect Exists

The application intentionally contains NO:

useEffect(...)

Why?

Because no external synchronization exists.

We are only calculating values during rendering.

This is one of the most important lessons in modern React.

Many beginners incorrectly write:

useEffect(() => {
setBmi(...)
}, [weight, height])

This is unnecessary.

React recommends calculating directly during rendering whenever possible.


The Role of Utility Functions

The calculations are separated into:

src/utils/bmiUtils.ts

This file contains:

export function calculateBmi(...)

and:

export function getBmiClassification(...)

This separation is extremely important architecturally.


Why Separate Logic from UI

The component should focus on:

  • rendering
  • interaction
  • composition

Utility files should focus on:

  • calculations
  • business rules
  • reusable logic

This separation improves:

BenefitExplanation
readabilitycleaner components
scalabilityeasier growth
testingisolated logic
reusefunctions reusable elsewhere
maintainabilitysmaller responsibilities

The Role of the TypeScript Model

The file:

BmiClassification.ts

contains:

export interface BmiClassification {
label: string;
color: string;
}

This defines the structure of the classification object.

TypeScript guarantees:

Every classification must contain:
- label
- color

This improves:

  • autocomplete
  • safety
  • architecture
  • refactoring

The React Render Cycle

One of the most important concepts introduced by this app is:

React automatically re-renders when state changes.

Flow:

User types
setWeight()
React schedules render
Component function executes again
BMI recalculates
UI updates

No manual DOM update exists.


Declarative UI

React is declarative.

You describe:

What the UI should look like

instead of:

How to manually manipulate the DOM

This is one of the central React Learn principles.


The Fluent UI Components

The application uses:

ComponentPurpose
CardContainer
FieldAccessible form wrapper
InputEnterprise text input
TextTypography
Title2Section title

Fluent UI provides:

  • accessibility
  • spacing
  • typography
  • keyboard navigation
  • Microsoft visual standards

Why Fluent UI Matters

Using Fluent UI means:

You do not manually recreate enterprise controls.

Instead, you compose enterprise-ready components.

This aligns with the project roadmap using Fluent UI as the standard design system.


Understanding Conditional Rendering

The classification changes dynamically:

<Text
style={{
color: classification.color,
}}
>
{classification.label}
</Text>

React recalculates:

  • label
  • color

based on BMI.

This creates dynamic UI.


Production Validation

Run the development server:

npm run dev

Validate production build:

npm run build

Preview production:

npm run preview

The build step validates:

  • TypeScript
  • JSX
  • imports
  • dependencies
  • production bundling

What This App Really Teaches

Visually:

It looks like a simple calculator.

Architecturally:

It teaches the correct React mental model.

The most important lessons are:

ConceptImportance
useStatecomponent memory
controlled inputsReact-driven forms
derived stateavoid duplicated state
render cycleautomatic UI updates
utility functionsseparation of concerns
TypeScriptsafe architecture
Fluent UIenterprise components
declarative renderingReact philosophy

Technical Summary

TechnologyPurpose
ReactDeclarative UI
TypeScriptStatic typing
ViteBuild tool
Fluent UIMicrosoft design system
useStateState management
Controlled InputsForm handling
Derived StateCalculated values
Utility FunctionsBusiness logic
JSXUI syntax
FlexboxLayout

Official Documentation

React

Fluent UI

Vite

TypeScript


Current Project Progress

BlockAppNameStatus
Block 101Hello React FluentCompleted
Block 102Profile CardCompleted
Block 103Product ListCompleted
Block 104Microsoft Style User CardCompleted
Block 105Static DashboardCompleted
Block 106Corporate Sidebar MenuCompleted
Block 107Visual Task ListCompleted
Block 108Timeline EventsCompleted
Block 109Employee TableCompleted
Block 110Email ListCompleted
Block 111Grid of CardsCompleted
Block 112Image GalleryCompleted
Block 113Movie CatalogCompleted
Block 114Football TeamsCompleted
Block 115News PageCompleted
Block 116Financial DashboardCompleted
Block 117SharePoint LayoutCompleted
Block 118File ExplorerCompleted
Block 119Corporate PortalCompleted
Block 120Microsoft Landing PageCompleted
Block 221Modern CounterCompleted
Block 222Toggle ThemeCompleted
Block 223React CalculatorCompleted
Block 224Login FormCompleted
Block 225User RegistrationCompleted
Block 226ToDo ListCompleted
Block 227Shopping ListCompleted
Block 228Product FilterCompleted
Block 229Employee SearchCompleted
Block 230Shopping CartCompleted
Block 231Grade SimulatorCompleted
Block 232Inventory ControlCompleted
Block 233Contact AgendaCompleted
Block 234Currency ConverterCompleted
Block 235BMI CalculatorCurrent
Block 236Installment SimulatorNext

Edvaldo Guimrães Filho Avatar

Published by