Project Idea: E-commerce Cart
This project is essential for every React developer's portfolio. We will build a professional-looking product page. When a user clicks 'Add to Cart', the item will be added to a global cart state. The user can then navigate to the `/cart` page to see all their items. The main focus is Global State Management using the Context API to avoid "prop drilling".
✨ Key Features
- A product page showing item details.
- "Add to Cart" button to add items to a global cart.
- A separate "Cart" page (`/cart`) to display all selected items.
- Ability to see the total number of items in the cart (e.g., in the navbar).
- A global state that is accessible from any component.
💻 Tech Stack & Skills
- Tech Stack: React, React Router, Context API, `useReducer` hook.
- Skills Practiced: Global State Management, `useContext` hook, `useReducer` hook, avoiding prop-drilling, React Router for navigation, managing complex app-wide state.
🛠️ Full Step-by-Step Tutorial
Let's build this. This tutorial assumes you have a React app set up with `react-router-dom` installed (`npm i react-router-dom`).
Step 1: File Structure
In your src folder, create a structure like this:
/src
/components
- Navbar.js
- ProductList.js
- CartPage.js
/context
- CartContext.js
- App.js
- index.js
- style.css (Your main CSS)
Step 2: Create the Cart Context (`CartContext.js`)
This is the heart of our app. We'll use `useReducer` because it's better for managing complex state (like a cart) than `useState`.
src/context/CartContext.jsimport React, { createContext, useContext, useReducer } from 'react';
// 1. Define the initial state
const initialState = {
items: [],
};
// 2. Create the reducer function
const cartReducer = (state, action) => {
switch (action.type) {
case 'ADD_TO_CART':
// (Add logic to handle duplicates if you want)
return {
...state,
items: [...state.items, action.payload],
};
case 'REMOVE_FROM_CART':
return {
...state,
items: state.items.filter(item => item.id !== action.payload.id),
};
default:
return state;
}
};
// 3. Create the Context
export const CartContext = createContext();
// 4. Create the Provider Component
export const CartProvider = ({ children }) => {
const [state, dispatch] = useReducer(cartReducer, initialState);
return (
{children}
);
};
// 5. Create a custom hook for easy access
export const useCart = () => {
return useContext(CartContext);
};
Step 3: Wrap Your App (`index.js`)
Now we must "provide" this context to our entire app.
src/index.jsimport React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { CartProvider } from './context/CartContext';
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
);
Step 4: Setup Routing (`App.js`)
Let's set up the pages for our app.
src/App.jsimport React from 'react';
import { Routes, Route } from 'react-router-dom';
import Navbar from './components/Navbar';
import ProductList from './components/ProductList';
import CartPage from './components/CartPage';
import './style.css'; // Assuming you have main styles
function App() {
return (
} />
} />
);
}
export default App;
Step 5: Create the `ProductList.js` Component
This component will show our products and let users add them to the cart.
src/components/ProductList.jsimport React from 'react';
import { useCart } from '../context/CartContext';
// Dummy product data
const dummyProducts = [
{ id: 1, name: 'React T-Shirt', price: 25 },
{ id: 2, name: 'Node.js Hoodie', price: 45 },
{ id: 3, name: 'JavaScript Mug', price: 15 },
];
function ProductList() {
// Get the dispatch function from our context
const { dispatch } = useCart();
const handleAddToCart = (product) => {
dispatch({
type: 'ADD_TO_CART',
payload: product,
});
};
return (
Products
{dummyProducts.map(product => (
{product.name}
${product.price}
))}
);
}
export default ProductList;
Step 6: Create the `CartPage.js` Component
This page will show items in the cart and let users remove them.
src/components/CartPage.jsimport React from 'react';
import { useCart } from '../context/CartContext';
function CartPage() {
// Get both state and dispatch from our context
const { state, dispatch } = useCart();
const handleRemove = (item) => {
dispatch({
type: 'REMOVE_FROM_CART',
payload: item,
});
};
const totalPrice = state.items.reduce((total, item) => total + item.price, 0);
return (
My Cart
{state.items.length === 0 ? (
Your cart is empty.
) : (
{state.items.map(item => (
{item.name} - ${item.price}
))}
Total: ${totalPrice}
)}
);
}
export default CartPage;
Step 7: Update the `Navbar.js` Component
Finally, let's show the cart count in the navbar.
src/components/Navbar.jsimport React from 'react';
import { Link } from 'react-router-dom';
import { useCart } from '../context/CartContext';
function Navbar() {
// Get the cart state
const { state } = useCart();
const cartCount = state.items.length;
return (
);
}
export default Navbar;
Aur yeh ho gaya! Ab aapke paas ek fully functional cart system hai jo poori app mein kahin se bhi access ho sakta hai.
🔥 Next Steps & Challenges
After completing this tutorial, try these ideas:
- **Handle Quantity:** Abhi humara cart sirf item add karta hai. Logic update karein taaki agar item pehle se cart mein hai, toh uski quantity badhe.
- **Local Storage:** Cart items ko `localStorage` mein save karein taaki page reload hone par bhi cart khali na ho.
- **Backend:** Ek fake API (like `fakestoreapi.com`) se products fetch karein instead of using dummy data.