🛍️ Building a React Shopping Cart Site: Lessons Learned from Real Challenges


Creating a fully functional shopping cart application with React was more than just a practice project, it was a deep dive into real-world development problems, state management, component design, and deployment strategies.
In this post, I’ll walk you through how I approached the project, the technical decisions I made, the custom tools I built (like a custom hook for quantity), and what I learned along the way.
Project Overview
This project was designed to simulate a basic e-commerce experience. The main features included:
A Home page, Shop page and a Cart page with routing between them
A responsive navigation bar shared across both pages
Product listings fetched from the FakeStore API
A fully interactive cart system with quantity selection
A badge in the navbar showing the number of items in the cart
Proper state updates when items are added/removed
Deployment as a single-page application (SPA)
Custom hook for managing product quantity
Testing using React Testing Library and Vitest
Creating a Custom Hook for Quantity Management
One of the standout decisions in this project was abstracting the quantity logic into a custom hook.
Instead of repeating useState
, onChange
, increment
, and decrement
logic across every product card, I created a hook like this:
import { useState } from 'react';
const useCartQuantity = (product, cartList, setCartList) => {
const [quantity, setQuantity] = useState(product.quantity || 1);
const updateQuantity = (newQuantity) => {
setQuantity(newQuantity);
const updatedCart = cartList.map((item) =>
item.id === product.id ? { ...item, quantity: newQuantity } : item
);
setCartList(updatedCart);
};
const incrementQuantity = (e) => {
e.preventDefault();
updateQuantity(quantity + 1);
};
const decrementQuantity = (e) => {
e.preventDefault();
if (quantity > 1) {
updateQuantity(quantity - 1);
}
};
return {
quantity,
setQuantity,
updateQuantity,
incrementQuantity,
decrementQuantity,
};
};
export default useCartQuantity;
Using this hook simplified my product card component and improved code readability and reusability.
Managing Cart State Across Components
Cart state management became a little tricky as it had to be:
Updated when items are added or modified
Shared between multiple components (product cards, navbar badge, cart page)
Reflect real-time updates like quantity changes
I used useState
and React context (or optionally a state management library like Redux) to lift the cart state to a higher-level component so it could be accessed and modified globally.
Fetching Data from the FakeStore API
To keep the app dynamic, I used the FakeStore API to fetch product data. Here’s a basic example:
useEffect(() => {
const fetchProducts = async () => {
try {
const res = await fetch('https://fakestoreapi.com/products');
const data = await res.json();
setProducts(data);
} catch (error) {
console.error('Error fetching products:', error);
}
};
fetchProducts();
}, []);
This taught me how to gracefully handle loading and error states while ensuring the UI stays responsive.
Writing Tests with React Testing Library
Testing was another valuable part of this project. I used React Testing Library to:
Simulate user interactions (clicks, input changes)
Assert changes in the DOM (cart updates, page content)
Avoid testing third-party libraries like
react-router-dom
directly
Example test for the cart count:
it('calculates and displays correct cart quantity', () => {
const mockCartList = [
{ id: 1, title: 'Product 1', quantity: 2 },
{ id: 2, title: 'Product 2', quantity: 3 },
];
render(
<MemoryRouter>
<Navbar cartList={mockCartList} />
</MemoryRouter>
);
expect(screen.getByText('5')).toBeInTheDocument();
});
Deploying as a Single Page App on Vercel
Once development was complete, I deployed the app to Vercel. But I ran into an issue: refreshing non-root routes resulted in a 404 error. That’s because SPAs need to serve index.html
for all routes.
To fix this, I added a vercel.json
file at the root of my project:
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/index.html"
}
]
}
Now Vercel knows to let React Router handle routing client-side.
Styling & User Experience
I kept the styling clean and user-friendly using a combination of CSS modules and utility classes. Each product card included:
Product image and title
Input field for quantity
Increment/decrement buttons
“Add to Cart” button
The navigation bar showed the current cart count and a link to view the cart for checkout.
What I Learned
Building this shopping cart project was a fantastic learning experience. Here's a quick summary of key takeaways:
Creating custom hooks improves code reusability and cleanliness
Lifting state up and managing it globally is essential for dynamic UIs
Deployment for SPAs requires route rewriting on platforms like Vercel
Testing user flows is better than testing implementation details
Styling and small UX touches really elevate the app's experience
Try it Out
đź”— Live Demo: https://affordrobe.vercel.app/
đź’» GitHub Repo: https://github.com/Shumaila-sayed/Affordrobe
Final Thoughts
If you’re learning React and want a project that puts your knowledge to the test, building a shopping cart is a perfect choice. You’ll touch nearly every key React concept: state, props, routing, custom hooks, API calls, testing, and deployment.
Let me know if you give it a try or want to collaborate on something similar!
#ReactJS #WebDevelopment #CustomHooks #WomenWhoCode #FrontendDevelopment #OpenToWork #Vercel #JavaScript #ReactTestingLibrary
Subscribe to my newsletter
Read articles from Shumaila Sayed directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Shumaila Sayed
Shumaila Sayed
On a journey to learn coding and contribute to open source.🥂 📌Currently learning Responsive web design