Diagram showing React shopping cart state management with user interaction, cart state, state updates, and UI re-renders

Technical Blog Article — App 30: Building a Shopping Cart with React, TypeScript, Vite, and Fluent UI

The Shopping Cart is one of the most important exercises in frontend engineering because it introduces a central React concept:

The interface is a function of state.

In App 30 — Shopping Cart, we move deeper into Block 2 of the React learning roadmap, focused on:

  • useState
  • immutable updates
  • derived state
  • event handling
  • array manipulation
  • component composition
  • state-driven rendering

The roadmap defines App 30 as “Carrinho de Compras / Shopping Cart”, specifically focused on derived state and React’s “Choosing the State Structure” mental model.

This application is extremely important because it simulates the type of logic found in:

  • e-commerce systems
  • ERP platforms
  • Microsoft-style enterprise portals
  • SharePoint business apps
  • inventory systems
  • admin dashboards

Even though the UI appears simple, architecturally this app introduces:

  • complex state updates
  • immutable patterns
  • functional state updates
  • array transformations
  • dynamic rendering
  • calculated totals
  • separation of concerns

Most importantly, this app teaches:

What should be stored in state?
What should be derived from state?

This distinction is one of the most important concepts in modern React.


1. Creating the Project

The project starts with Vite + React + TypeScript.

PowerShell Commands

cd C:\ReactApps
mkdir bloco02
cd bloco02
npm create vite@latest app30-shopping-cart -- --template react-ts
cd app30-shopping-cart
npm install
npm install @fluentui/react-components @fluentui/react-icons

This creates:

  • React
  • TypeScript
  • Vite
  • Fluent UI
  • development environment
  • build configuration

2. Creating the Folder Structure

Professional React applications require organization from the beginning.

PowerShell

mkdir src\components
mkdir src\data
mkdir src\models

The architecture becomes:

src/
components/
data/
models/

3. Why This Structure Matters

Each folder has a responsibility.

FolderResponsibility
components/Reusable UI blocks
data/Static/mock data
models/TypeScript types/interfaces

This separation prevents chaos as applications grow.


4. The Product Model

src/models/Product.ts

export interface Product {
id: number;
name: string;
category: string;
price: number;
}
export interface CartItem extends Product {
quantity: number;
}

This file introduces an extremely important TypeScript concept:

Interface extension

5. Understanding extends

export interface CartItem extends Product

This means:

CartItem contains ALL Product properties
PLUS quantity

Conceptually:

Product
id
name
category
price
CartItem
id
name
category
price
quantity

This is very important because it avoids duplication.

Without extends, you would repeat all fields manually.


6. Why Models Matter in React

The model defines the shape of the data.

React applications become dramatically easier to understand when data structures are explicit.

Benefits:

  • autocomplete
  • validation
  • safer refactoring
  • fewer runtime bugs
  • better scalability
  • predictable architecture

7. The Product Data Source

src/data/products.ts

import type { Product } from "../models/Product";
export const products: Product[] = [
{ id: 1, name: "Surface Laptop", category: "Hardware", price: 1299 },
{ id: 2, name: "Microsoft 365", category: "Software", price: 99 },
{ id: 3, name: "Teams Premium", category: "Collaboration", price: 120 },
];

This introduces another critical React idea:

The UI should derive from data.

Instead of manually creating cards one by one, React uses data structures and renders dynamically.


8. Why the Array Matters

This array becomes the source of truth.

React later transforms this:

[
Product 1,
Product 2,
Product 3
]

into:

[
ProductCard,
ProductCard,
ProductCard
]

using:

products.map(...)

This is declarative rendering.


9. The ProductCard Component

src/components/ProductCard.tsx

This component is responsible for rendering one product.

interface ProductCardProps {
product: Product;
onAddToCart: (product: Product) => void;
}

This introduces props with functions.


10. Functions as Props

One of React’s most important concepts is:

Parent components can send behavior to child components.

The prop:

onAddToCart

is not data.

It is behavior.

This means:

  • the child component can trigger actions
  • the parent keeps control of state
  • state remains centralized

This is foundational React architecture.


11. The Add Button

<Button
appearance="primary"
icon={<Add24Regular />}
onClick={() => onAddToCart(product)}
>
Add to cart
</Button>

This line introduces:

  • events
  • callbacks
  • function execution
  • React event system

12. Understanding onClick

onClick={() => onAddToCart(product)}

This is extremely important.

We are NOT doing:

onClick={onAddToCart(product)}

because that would execute immediately during render.

Instead:

() => onAddToCart(product)

creates a function that React executes later when the user clicks.


13. React Event Flow

The flow becomes:

User clicks button
Button triggers onClick
onAddToCart(product)
Parent updates state
React re-renders UI

This is the core React rendering cycle.


14. The Root State

Inside App.tsx:

const [cartItems, setCartItems] = useState<CartItem[]>([]);

This is the central state of the application.


15. Understanding useState

React state is component memory.

The syntax:

const [cartItems, setCartItems]

creates:

  • current value
  • update function

Conceptually:

cartItems
current cart memory
setCartItems
function that changes cart memory

16. Why the State Starts Empty

useState<CartItem[]>([])

The initial cart is empty.

This means:

No products added yet.

The UI later changes dynamically based on this array.


17. The Add-To-Cart Algorithm

The most important logic in the app is:

function addToCart(product: Product)

This function must:

  1. check if product already exists
  2. increase quantity if found
  3. create new item if not found

18. Functional State Updates

setCartItems((currentItems) => {

This is a functional state update.

This is the safest pattern when the next state depends on the previous state.

React Learn strongly recommends this pattern.


19. Why Functional Updates Matter

Bad pattern:

setCartItems([...cartItems, item])

Safer pattern:

setCartItems((currentItems) => ...)

Why?

Because React state updates may be asynchronous.

Functional updates always use the latest state snapshot.


20. Finding Existing Products

const existingItem = currentItems.find(
(item) => item.id === product.id
);

This checks whether the cart already contains the product.

Possible result:

  • item found
  • undefined

21. Updating Existing Quantity

return currentItems.map((item) =>
item.id === product.id
? { ...item, quantity: item.quantity + 1 }
: item
);

This is one of the most important React patterns.


22. Why map() Is Used

map() transforms arrays immutably.

We are NOT changing the original array.

We are creating a NEW array.

This is critical because React expects immutable updates.


23. Understanding Immutable Updates

React state should NEVER be mutated directly.

Bad:

item.quantity++;

Correct:

{ ...item, quantity: item.quantity + 1 }

This creates a NEW object.


24. The Spread Operator

{ ...item, quantity: item.quantity + 1 }

This copies:

  • id
  • name
  • category
  • price

and replaces:

  • quantity

Conceptually:

Old object
copied
quantity
updated

25. Adding a New Product

If the product does not exist:

return [...currentItems, { ...product, quantity: 1 }];

This:

  • copies old items
  • appends a new object

Again:

  • immutable update
  • no mutation

26. Increasing Quantity

function increaseQuantity(id: number)

This uses:

map()

to create a new array with one updated item.


27. Decreasing Quantity

function decreaseQuantity(id: number)

This demonstrates array chaining:

.map(...)
.filter(...)

28. Why .filter() Is Used

If quantity reaches zero:

remove the item entirely

This is achieved with:

.filter((item) => item.quantity > 0)

This is elegant React state management.


29. Removing Items Completely

function removeItem(id: number)

This uses:

filter()

to remove items immutably.


30. The CartSummary Component

This component introduces derived state.


31. Derived State

This is one of the most important concepts in React.

Notice:

const totalItems = ...
const totalPrice = ...

We are NOT storing totals in state.

This is intentional.


32. Why Totals Should NOT Be Stored

Bad architecture:

const [totalPrice, setTotalPrice]

Why bad?

Because:

  • duplicated state
  • synchronization problems
  • bugs
  • unnecessary complexity

Instead:

Totals are CALCULATED from cartItems.

This is React’s recommended mental model.


33. Calculating Totals with reduce()

cartItems.reduce(...)

reduce() converts an array into a single value.


34. Total Items Calculation

const totalItems = cartItems.reduce(
(sum, item) => sum + item.quantity,
0
);

Flow:

0 + quantity1 + quantity2 + quantity3

35. Total Price Calculation

const totalPrice = cartItems.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);

Flow:

subtotal1 + subtotal2 + subtotal3

36. Why This Is Powerful

The totals automatically stay correct because they derive from state.

This means:

  • fewer bugs
  • simpler logic
  • predictable UI

37. Component Composition

The hierarchy becomes:

App
ProductCard
ProductCard
ProductCard
CartSummary

This is classic React composition.


38. The Main Layout

display: "grid",
gridTemplateColumns: "2fr 1fr",

This creates:

  • products area
  • cart sidebar

Very common in e-commerce systems.


39. Fluent UI Components Used

This app uses:

  • Card
  • Button
  • Text
  • Title1
  • Title2
  • Title3

These provide:

  • Microsoft styling
  • accessibility
  • typography consistency
  • enterprise design language

40. Why Fluent UI Matters Here

Without Fluent UI:

  • buttons
  • spacing
  • typography
  • accessibility
  • focus management

would require manual implementation.

Fluent UI dramatically accelerates enterprise UI development.


41. Why This App Is Important

This app introduces:

  • real state management
  • immutable updates
  • event handling
  • derived state
  • reusable components
  • parent-child communication
  • React rendering flow

This is the foundation for:

  • inventory systems
  • admin dashboards
  • ERP platforms
  • SharePoint business apps
  • enterprise commerce systems

42. React Mental Model Reinforced

This app reinforces the correct React mental model:

State changes
React re-renders
UI automatically updates

Not:

  • manual DOM manipulation
  • imperative UI updates
  • jQuery-style logic

43. No useEffect Yet — And That Is Correct

Notice:

  • no useEffect
  • no synchronization
  • no API calls

That is GOOD.

According to React Learn — You Might Not Need an Effect

you should avoid effects when pure rendering logic is enough.

This app is fully driven by:

  • state
  • props
  • rendering

No effects are necessary.


Technical Summary

ConceptExplanation
useStateComponent memory
Functional updatesSafest state update pattern
map()Immutable array transformation
filter()Removing items immutably
reduce()Derived totals
Derived stateCalculated, not stored
PropsParent-child communication
Event handlingUser interaction
Fluent UIEnterprise Microsoft design system
TypeScript interfacesStrong typing

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 226Complete ToDo ListCompleted
Block 227Shopping ListCompleted
Block 228Product FilterCompleted
Block 229Employee SearchCompleted
Block 230Shopping CartCurrent Article Completed
Edvaldo Guimrães Filho Avatar

Published by