Build a Shopping Cart App with React, TypeScript, and Material-UI
Building a modern shopping cart application is a great way to learn React, TypeScript, and Material-UI. In this article, I'll walk you through a project where I implemented a responsive and dynamic shopping cart using React, TypeScript, Material-UI, and react-query.
Features of the Application
Hereβs what this app can do:
- Display a list of products fetched from an API.
- Add products to a shopping cart.
- Update the quantity of items in the cart.
- Calculate the total price of items in the cart.
- Use Material-UI components for a modern UI.
- Handle asynchronous data fetching using
react-query
.
Project Overview
Tech Stack
- React: For building the user interface.
- TypeScript: For type safety and better code maintainability.
- Material-UI (MUI): For styling and pre-built components.
- react-query: For efficient data fetching and caching.
- styled-components: For custom styling.
Folder Structure
The project follows a modular structure:
src/
βββ components/
β βββ Cart/
β β βββ Cart.tsx
β β βββ Cart.styles.ts
| βββ CartItem/
β β βββ CartItem.tsx
β β βββ CartItem.styles.ts
β βββ Item/
β β βββ Item.tsx
β β βββ Item.styles.ts
| |
βββ App.tsx
βββ App.styles.ts
βββ index.tsx
Step-by-Step Implementation
1. Define Types for Product Data**
TypeScript makes it easy to define the structure of the product data:
export type CardItemType = {
id: number;
category: string;
description: string;
image: string;
price: number;
title: string;
amount: number;
};
2. Fetch Data with react-query
We fetch product data from FakeStore API using react-query
:
const getProducts = async (): Promise<CardItemType[]> =>
await (await fetch('https://fakestoreapi.com/products')).json();
const { data, isLoading, error } = useQuery<CardItemType[]>('products', getProducts);
3. Build the UI
Product List (Item.tsx
)
The Item component displays individual products and includes a button to add the product to the cart.
const Item: React.FC<Props> = ({ item, handleAddToCart }) => (
<Wrapper>
<img src={item.image} alt={item.title} />
<div>
<h3>{item.title}</h3>
<p>{item.description}</p>
<h3>${item.price}</h3>
</div>
<Button onClick={() => handleAddToCart(item)}>Add to cart</Button>
</Wrapper>
);
**Shopping Cart (Cart.tsx
)
The Cart
component displays items in the cart and calculates the total price.
const Cart: React.FC<Props> = ({ cartItems, addToCart, removeFromCart }) => {
const calculateTotal = (items: CardItemType[]) =>
items.reduce((ack: number, item) => ack + item.amount * item.price, 0);
return (
<Wrapper>
<h2>Your Shopping Cart</h2>
{cartItems.length === 0 ? <p>No items in cart.</p> : null}
{cartItems.map((item) => (
<CartItem
key={item.id}
item={item}
addToCart={addToCart}
removeFromCart={removeFromCart}
/>
))}
<h2>Total: ${calculateTotal(cartItems).toFixed(2)}</h2>
</Wrapper>
);
};
4. Add Styling
We used styled-components
for custom styles. For example, hereβs the Wrapper
for the Item
component:
export const Wrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: space-between;
border: 1px solid lightblue;
border-radius: 10px;
height: 100%;
overflow: hidden;
img {
max-height: 250px;
object-fit: cover;
}
button {
background-color: #1976d2;
color: white;
font-weight: bold;
&:hover {
background-color: #1565c0;
}
}
`;
5. Manage Cart State
We used useState
to manage the cart state in App.tsx
:
const [cartItems, setCartItems] = useState<CardItemType[]>([]);
const handleAddToCart = (clickedItem: CardItemType) => {
setCartItems((prevState) => {
const isItemInCart = prevState.find((item) => item.id === clickedItem.id);
if (isItemInCart) {
return prevState.map((item) =>
item.id === clickedItem.id ? { ...item, amount: item.amount + 1 } : item
);
}
return [...prevState, { ...clickedItem, amount: 1 }];
});
};
const handleRemoveFromCart = (id: number) => {
setCartItems((prevState) =>
prevState.reduce((ack, item) => {
if (item.id === id) {
if (item.amount === 1) return ack;
return [...ack, { ...item, amount: item.amount - 1 }];
} else {
return [...ack, item];
}
}, [] as CardItemType[])
);
};
Conclusion
This project demonstrates how to create a fully functional shopping cart using modern React and TypeScript. You can enhance it further by adding features like user authentication, payment integration, or state management libraries like Redux or Zustand.
Top comments (2)
Good article.
Thanks for sharing.
But it would be better if you could style the format of folder structure so that the others can easily understand it.
Hello, thank you for your feedback.
I've changed the folder structure, and it's much easier to read.