Stop 08 · ReactProjects · 1/6

Ecommerce

Part of the Frontend Developer Roadmap

In short

An online store is the classic React project because it uses almost everything: lists, routing, shared cart state and forms. Build a small one properly and most React apps will feel familiar.

A product listing, cart and checkout flow — one of the most common real-world React apps, combining state management, routing and forms.

The jaadu mascot pushes a full trolley down a supermarket aisle toward the billing counter.

Think of it like this

A supermarket trip

You walk the aisles (product list), pick something up to read the label (product page), drop it in the trolley (cart) and pay at the counter (checkout). Your app needs each of these stations, and the trolley has to follow you everywhere.

Watch it happen

Add to cart, everywhere at once

ProductCard
Cart reducer
Header badge
Cart page

{type: "add", item}

1/4The cart has one ₹20 pen and one ₹60 notebook. You click Add on the pen again.

The big ideas

What you need to know

Product list and filters

Show products from a JSON file or a free API, with a search box and a category filter.

A cart that's everywhere

Keep cart state in Context (or Zustand later) so the header badge and the cart page always agree.

Real routes

/, /product/:id, /cart and /checkout, linked with Link so the cart survives every page change.

Derived totals

Work out item count and total from the cart array. Don't store them separately.

How it works

Build plan

  1. 1

    Static product grid

    Render products from a local JSON file with a ProductCard component.

  2. 2

    Add routing

    Create the product detail page and read the id with useParams.

  3. 3

    Cart state

    Add, remove and change quantities from one shared cart.

  4. 4

    Checkout form

    Collect address details and show an order summary.

  5. 5

    Save the cart

    Store it in localStorage so a refresh doesn't empty it.

See it in code

Walk through the code

ts
1type Item = { id: number; name: string; price: number; qty: number };2type Action = { type: "add"; item: Omit<Item, "qty"> } | { type: "remove"; id: number };3 4export function cartReducer(cart: Item[], action: Action): Item[] {5  switch (action.type) {6    case "add": {7      const found = cart.find((i) => i.id === action.item.id);8      if (found) return cart.map((i) => (i.id === found.id ? { ...i, qty: i.qty + 1 } : i));9      return [...cart, { ...action.item, qty: 1 }];10    }11    case "remove":12      return cart.filter((i) => i.id !== action.id);13  }14}15 16// const total = cart.reduce((sum, i) => sum + i.price * i.qty, 0);

1/4Types for one cart line and the two actions the reducer understands.

Use it with useReducer(cartReducer, []). Adding the same product twice bumps its quantity instead of creating a duplicate line.

Save yourself the pain

Common mistakes

Oops

Keeping cartTotal in its own state and updating it by hand.

Do this instead

Calculate the total from the cart on every render. One source of truth, no mismatched numbers.

Oops

Storing prices like 19.99 and getting totals like 0.30000000000000004.

Do this instead

Store prices as whole numbers (paise), and format them with Intl.NumberFormat only when showing them.

Oops

Trusting the price the browser sends at checkout.

Do this instead

A real store looks prices up on the server. For this project, at least remember that client prices can be edited.

Your mission

First milestone: a working cart

~45 min

Quick check

The cart has [{ price: 500, qty: 2 }, { price: 200, qty: 1 }]. What's the total, and where should it come from?

Go deeper

  1. 1Manage cart state with Context or a lightweight state library.
  2. 2Implement product filtering/sorting and a persistent cart (localStorage).
  3. 3Build a multi-step checkout form with validation.

More projects at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge