React shopping list app state diagram showing components, states, and events

Technical Blog Article — App 27: Building a Shopping List with React State, map(), filter(), and Fluent UI

The twenty-seventh application in the React + Fluent UI learning roadmap is App 27 — Shopping List. This application belongs to Block 2 — Interactivity and State, the phase where the project transitions from static UI composition into dynamic interfaces driven by React state. The roadmap defines this app as a dynamic list focused on map() and filter() rendering.

At first glance, a shopping list may appear simple. However, architecturally this application introduces several extremely important React concepts that are foundational for all modern React development:

  • useState
  • controlled inputs
  • immutable updates
  • array rendering
  • map()
  • filter()
  • derived state
  • component composition
  • event handling
  • Fluent UI enterprise components

This app is especially important because it teaches one of the core React mental models:

The UI is a function of state.

Instead of manually manipulating HTML elements, React applications update the UI automatically whenever state changes.

This is the beginning of true React thinking.


1. The Goal of the Application

The application simulates a modern enterprise shopping list interface where users can:

  • add items
  • toggle purchased status
  • remove items
  • clear completed items
  • visualize totals dynamically

The app uses:

  • React
  • TypeScript
  • Vite
  • Fluent UI

and follows the architectural principles defined by the official React Learn documentation:

  • declarative rendering
  • immutable state updates
  • component composition
  • derived state
  • pure rendering logic

2. Project Creation

The project begins with Vite.

Why Vite?

Vite is the modern standard development environment for React applications because it provides:

  • extremely fast startup
  • instant hot reload
  • modern ES module support
  • optimized production builds
  • lightweight configuration

Project creation:

cd C:\ReactApps
mkdir bloco02
cd bloco02
npm create vite@latest app27-shopping-list -- --template react-ts

This command creates:

  • a React project
  • TypeScript configuration
  • Vite configuration
  • development scripts
  • base folder structure

3. Installing Dependencies

After creating the project:

cd app27-shopping-list
npm install

Then Fluent UI is installed:

npm install @fluentui/react-components @fluentui/react-icons

Fluent UI provides:

  • enterprise components
  • accessibility support
  • Microsoft design standards
  • typography systems
  • layout consistency

4. Creating the Folder Structure

Folders:

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

Files:

New-Item src\models\ShoppingItem.ts -ItemType File
New-Item src\data\initialShoppingItems.ts -ItemType File
New-Item src\components\ShoppingListApp.tsx -ItemType File
New-Item src\components\ShoppingItemCard.tsx -ItemType File

This structure is extremely important.

Modern React applications should separate responsibilities.


5. Understanding the Architecture

The application structure becomes:

src/
components/
ShoppingListApp.tsx
ShoppingItemCard.tsx
models/
ShoppingItem.ts
data/
initialShoppingItems.ts
styles/
App.tsx
main.tsx
index.css

Each folder has a specific responsibility.


6. The TypeScript Model

File:

src/models/ShoppingItem.ts

Code:

export interface ShoppingItem {
id: number;
name: string;
quantity: number;
category: string;
purchased: boolean;
}

This file defines the shape of a shopping item.

This is one of the most important concepts in TypeScript:

  • defining data contracts

Each shopping item must contain:

PropertyType
idnumber
namestring
quantitynumber
categorystring
purchasedboolean

7. Why Interfaces Matter

Without TypeScript, mistakes like this could happen:

quantity: "five"

But TypeScript prevents this because quantity must be a number.

Benefits:

  • autocomplete
  • validation
  • safer refactoring
  • better maintainability
  • enterprise scalability

8. The Initial Data File

File:

src/data/initialShoppingItems.ts

Code:

import type { ShoppingItem } from "../models/ShoppingItem";
export const initialShoppingItems: ShoppingItem[] = [
{ id: 1, name: "Milk", quantity: 2, category: "Dairy", purchased: false },
{ id: 2, name: "Bread", quantity: 1, category: "Bakery", purchased: true },
{ id: 3, name: "Apples", quantity: 6, category: "Fruit", purchased: false },
];

This introduces another core React idea:

UI should be derived from data.

The interface is not hardcoded manually.

Instead:

  • data exists
  • React transforms data into UI

9. Understanding useState

Inside:

ShoppingListApp.tsx

we find:

const [items, setItems] =
useState<ShoppingItem[]>(initialShoppingItems);

This is one of the most important lines in the entire application.


10. The React State Pattern

This syntax:

const [items, setItems] = useState(...)

creates:

  • a state variable
  • a function that updates the state

Conceptually:

items
current application data
setItems
function used to replace the data

React re-renders automatically whenever setItems() is called.


11. Why React State Is Different

In traditional JavaScript, developers manually updated HTML.

Example:

find element
change text
append HTML
remove nodes

React works differently.

Instead:

  • state changes
  • React calculates UI changes
  • React updates the DOM automatically

This is declarative UI rendering.


12. Controlled Inputs

The app also contains:

const [name, setName] = useState("");
const [quantity, setQuantity] = useState("1");
const [category, setCategory] = useState("");

These states control the form inputs.

Example:

<Input
value={name}
onChange={(_, data) => setName(data.value)}
/>

This is called a controlled component.

The input value comes from React state.


13. Why Controlled Inputs Matter

React becomes the source of truth.

Instead of reading values directly from the DOM, React already knows the current values.

Benefits:

  • validation
  • predictable behavior
  • centralized state
  • easier debugging

14. Adding New Items

Function:

function handleAddItem() {

This function:

  1. validates inputs
  2. creates a new object
  3. updates state

15. Creating the New Object

const newItem: ShoppingItem = {
id: Date.now(),
name: name.trim(),
quantity: Number(quantity),
category: category.trim(),
purchased: false,
};

Important concepts:

  • object creation
  • TypeScript typing
  • string cleanup
  • numeric conversion

16. Why Date.now() Is Used

id: Date.now()

This generates a unique numeric ID.

React lists require stable keys.


17. Updating Arrays in React

The most important line:

setItems((currentItems) => [...currentItems, newItem]);

This introduces immutable updates.


18. Why Immutable Updates Matter

React state should NEVER be modified directly.

Wrong:

items.push(newItem)

Correct:

[...currentItems, newItem]

This creates:

  • a new array
  • preserving immutability

React detects:

  • old array
  • new array

and re-renders.


19. Understanding the Spread Operator

...currentItems

This copies all previous array items.

Conceptually:

old items
+
new item
=
new array

20. Resetting the Form

After insertion:

setName("");
setQuantity("1");
setCategory("");

This resets the form visually.

Because inputs are controlled by state, changing state changes the UI.


21. Toggling Purchased State

Function:

function handleTogglePurchased(id: number)

This updates one specific item.


22. Using map() for Updates

currentItems.map((item) =>

This is extremely important.

map() transforms arrays.

React commonly uses:

  • map() for rendering
  • map() for updating

23. Immutable Object Updates

Inside map():

item.id === id
? { ...item, purchased: !item.purchased }
: item

This means:

If this is the correct item:
create a new object
invert purchased value
Otherwise:
keep original item

24. Why Object Spread Matters

{ ...item, purchased: !item.purchased }

This copies:

  • all old properties

and changes only:

  • purchased

Again:

  • immutable updates
  • predictable rendering

25. Deleting Items with filter()

Function:

function handleDeleteItem(id: number)

Uses:

filter((item) => item.id !== id)

This creates:

  • a new array
  • without the deleted item

26. Understanding filter()

filter() keeps items matching a condition.

Conceptually:

Keep every item
EXCEPT
the deleted one

This is another core React pattern.


27. Clearing Purchased Items

Function:

handleClearPurchased()

Uses:

filter((item) => !item.purchased)

Meaning:

Keep only non-purchased items

28. Derived State

The app calculates:

const totalItems = items.length;
const purchasedItems =
items.filter((item) => item.purchased).length;
const pendingItems =
items.filter((item) => !item.purchased).length;

This introduces one of the most important React concepts:

Derived state.


29. Why Derived State Matters

We DO NOT store:

  • totalItems
  • purchasedItems
  • pendingItems

inside state.

Instead, we calculate them from existing data.

This follows React Learn guidance:

Avoid redundant state.


30. Rendering with map()

The UI rendering:

{items.map((item) => (

converts:

  • data array
    into:
  • component array

31. Component Composition

Structure:

App
ShoppingListApp
ShoppingItemCard

This is React composition.

Each component has one responsibility.


32. The ShoppingItemCard

This component receives props:

interface ShoppingItemCardProps {
item: ShoppingItem;
onTogglePurchased: (id: number) => void;
onDeleteItem: (id: number) => void;
}

This teaches:

  • props
  • callback functions
  • parent-child communication

33. Callback Functions

The child component does NOT directly modify state.

Instead:

  • it calls parent functions

Example:

onTogglePurchased(item.id)

This is very important architecturally.

State lives in the parent component.


34. Why State Is Centralized

This pattern is called:

  • lifting state up

Benefits:

  • predictable updates
  • centralized logic
  • easier debugging

35. Fluent UI Components

The app uses:

ComponentPurpose
CardItem container
ButtonActions
InputForm fields
CheckboxPurchased toggle
BadgeCategory display
TextTypography

36. Why Fluent UI Matters

Fluent UI provides:

  • accessibility
  • keyboard navigation
  • Microsoft design language
  • responsive behavior
  • enterprise consistency

Without Fluent UI, all styling would need manual implementation.


37. Responsive Grid Layout

The app uses:

gridTemplateColumns:
"repeat(auto-fit, minmax(260px, 1fr))"

This creates a responsive layout.

Meaning:

Create as many columns as fit.
Each card must be at least 260px wide.

38. React Rendering Flow

Complete rendering flow:

main.tsx
renders App
App
renders ShoppingListApp
ShoppingListApp
stores state
renders ShoppingItemCard list
ShoppingItemCard
displays each item

39. Why No useEffect Yet?

This app intentionally avoids:

  • useEffect
  • APIs
  • external synchronization

Because React Learn teaches:

Effects are for synchronizing with external systems.

This app only manages internal state.

So useState is enough.


40. What This App Really Teaches

Even though visually simple, this app introduces the foundation of:

  • CRUD logic
  • enterprise state updates
  • immutable rendering
  • dynamic UI composition

These same patterns will later evolve into:

  • dashboards
  • API grids
  • Kanban boards
  • admin portals
  • enterprise systems

Technical Summary

ConceptExplanation
useStateStores component memory
Controlled InputsReact controls form values
Immutable UpdatesState is replaced, never mutated
map()Transforms arrays
filter()Removes or selects items
Derived StateValues calculated from existing state
PropsComponent inputs
Callback FunctionsChild-to-parent communication
Fluent UIMicrosoft enterprise design system
TypeScript InterfacesData contracts

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 221Modern CounterCompleted
Block 222Toggle ThemeCompleted
Block 223React CalculatorCompleted
Block 224Login FormCompleted
Block 225User RegistrationCompleted
Block 226Complete ToDo ListCompleted
Block 227Shopping ListCurrent
Block 228Product FilterNext
Edvaldo Guimrães Filho Avatar

Published by