Implementing an E-Commerce "Add to Cart" Feature in React: A Step-by-Step Guide

rohitashsingh89

Rohitash Singh

Posted on January 22, 2024

Implementing an E-Commerce "Add to Cart" Feature in React: A Step-by-Step Guide

Introduction
The world of e-commerce has witnessed a tremendous surge in recent years, and building a seamless shopping experience is crucial for the success of any online store. One of the fundamental features in any e-commerce application is the "Add to Cart" functionality, allowing users to easily select and store items they wish to purchase. In this blog, we will explore how to implement the "Add to Cart" feature using React, a popular JavaScript library for building user interfaces.

Prerequisites
Before diving into the implementation, make sure you have Node.js and npm (Node Package Manager) installed on your machine. You can create a new React application using Create React App:

npx create-react-app ecommerce-cart
cd ecommerce-cart
npm start

Enter fullscreen mode Exit fullscreen mode

Now, let's start implementing the "Add to Cart" functionality.

Step 1: Set Up the Project Structure
Organize your project by creating a dedicated folder structure. For simplicity, let's create a 'components' folder to store our React components.

src
|-- components
|   |-- AddToBasketList.js
|   |-- Basket.js
|   |-- BasketItem.js
|   |-- BasketCard.js
|   |-- TotalPrice.js
|-- context
|   |-- CartContext.js

Enter fullscreen mode Exit fullscreen mode

Step 2: Create Product and Cart Components
In Basket.js, create a list of products that users can add to their shopping cart:

import React from 'react';
import basketData from '../data.js/basketData';
import BankCard from './BankCard';
import BasketCard from './BasketCard';
import SlideCarousel from './Carousel';
import CategoryList from './CategoryList';
import DailyStapleCard from './DailyStapleCard';
import GroceryText from './GroceryText';

function Basket() {
    return (
        <>
            <div className='container custom-container'>
                <div className='row'>
                    <div className='header-category d-flex w-100'>
                        <CategoryList />
                    </div>

                    <div className='col-lg-12 my-4 discounted-img'>
                        <img src="https://source.unsplash.com/300x200/?grapes" className='img-fluid w-100' alt="discount show" style={{height: "250px", borderRadius: "20px"}} />
                        <span className='text-on-discounted-img text-center'>
                            <p className='m-0 p-0'>Upto</p>
                            <p className='m-0 p-0'>20%</p>
                        </span>
                    </div>

                    <h1>My Smart Basket</h1>

                    {basketData.slice(0,8).map((item) => (
                        <BasketCard item={item} key={item.id} />
                    ))}



                </div>
            </div>
        </>
    )
}

export default Basket;

Enter fullscreen mode Exit fullscreen mode

assume you have a list of basketData like

const basketData = [
    {
        id: 1,
        imgSrc: "https://source.unsplash.com/300x200/?banana",
        category: "Fresh",
        name: "Banana",
        amount: "1kg",
        discounted_price: "59.13",
        actual_price: "81",
        sale: "Get it for just ₹56.17!",
        off_on_product: "27",
        count: 1,
    },
];
export default basketData;

Enter fullscreen mode Exit fullscreen mode

AddToBasketList.js

import React, { useEffect, useState } from 'react';
import { useCart } from '../context/CartContext';
import BasketItem from './BasketItem';
import TotalPrice from './TotalPrice';

function AddToBasketList() {
  const { cartItems, removeFromCart,totalPrice } = useCart();

  const handleDeleteItem = (deletedItem, deletedPrice) => {
    removeFromCart(deletedItem, deletedPrice);
  };  

  return (
    <>
      <div className="container custom-container mb-5">
        <p className='mt-3'>My Basket</p>

        {cartItems.map((item, index) => (
          <BasketItem 
          index={index} 
          key={index} 
          item={item} 
          onDelete={(deletedItem, deletedPrice) => handleDeleteItem(deletedItem, deletedPrice)}  />
        ))}        

        <TotalPrice />
      </div>
    </>
  )
}

export default AddToBasketList;

Enter fullscreen mode Exit fullscreen mode

BasketCard.js

import React from 'react';
import { Link } from 'react-router-dom';
import { useCart } from '../context/CartContext';

function BasketCard({ item }) {
  const { addToCart } = useCart();

  const handleAddToCartClick = (item) => {
    addToCart(item, item.discounted_price);
  };

  return (
    <>
      <div className="col-lg-3 item-card" key={item.id}>
        <div className='shadow'>
          <div className="card mb-4 p-2">
            <Link to={`/details/${item.id}`}>
            <img src={item.imgSrc} className="card-img-top" alt="bigbasket item" />
            </Link>
            <span className='off_on_product bg-success p-2'>{item.off_on_product}% OFF</span>
            <div className="card-body">
              <p className="text-sm">{item.category}</p>
              <h5 className="card-title">{item.name}</h5>
              <div className="mb-3">
                <label htmlFor="exampleSelect" className="form-label">Select an option:</label>
                <select className="form-select" id="exampleSelect">
                  <option value="" >{item.amount}</option>
                  <option value="option1">Option 1</option>
                  <option value="option2">Option 2</option>
                  <option value="option3">Option 3</option>
                </select>
              </div>
              <h5 className="card-title">{item.discounted_price} <span className='text-decoration-line-through'>{item.actual_price}</span></h5>

              <div className="mb-3">
                <label htmlFor="exampleSelect" className="form-label">Select an option:</label>
                <select className="form-select" id="exampleSelect">
                  <option value="">{item.sale}</option>
                  <option value="option1">Option 1</option>
                  <option value="option2">Option 2</option>
                  <option value="option3">Option 3</option>
                </select>
              </div>

              <div className="d-flex">
                <span className='p-1 px-2 border me-2' title='Add to Fav'>
                  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-bookmark" viewBox="0 0 16 16">
                    <path d="M2 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v13.5a.5.5 0 0 1-.777.416L8 13.101l-5.223 2.815A.5.5 0 0 1 2 15.5zm2-1a1 1 0 0 0-1 1v12.566l4.723-2.482a.5.5 0 0 1 .554 0L13 14.566V2a1 1 0 0 0-1-1z" />
                  </svg>
                </span>
                <span className='w-100'>
                  <button className='btn btn-outline-danger w-100' onClick={() => handleAddToCartClick(item)}>Add</button>
                </span>
              </div>

            </div>
          </div>
        </div>
      </div>
    </>
  )
}

export default BasketCard;

Enter fullscreen mode Exit fullscreen mode

BasketItem.js

import React, { useEffect } from 'react';
import { useState } from 'react';
import { useCart } from '../context/CartContext';

function BasketItem({ onDelete, item, index, getCount, updateTotalPrice }) {
  let previousCount = JSON.parse(localStorage.getItem(`cartCount_${index}`)) || 1;
  let [count, setCount] = useState(previousCount);
  let { setTotalPrice } = useCart();


  useEffect(() => {
    localStorage.setItem(`cartCount_${index}`, JSON.stringify(count));
  }, [count, index]);


  let discountedPrice = (item.discounted_price * count).toFixed(2);
  let actualPrice = (item.actual_price * count).toFixed(2);
  let savePrice = (actualPrice - discountedPrice).toFixed(2);

  if (count < 1) {
    alert("You can't select 0 Item")
    count = 1
    discountedPrice = (item.discounted_price * count).toFixed(2);
    savePrice = (item.actual_price - item.discounted_price).toFixed(2);
  }

  const handleDelete = () => {
    onDelete(item, discountedPrice);
  };

  const handleIcrCount = (index) => {
    setCount(() => {
      const updatedCounts = count + 1
      setTotalPrice((prevTotalPrice) => prevTotalPrice + (item.discounted_price * 1));
      localStorage.setItem(`cartCount_${index}`, JSON.stringify(updatedCounts));
      return updatedCounts;
    });
  };

  const handleDcrCount = (index) => {
    setCount(() => {
      const updatedCounts = count - 1
      setTotalPrice((prevTotalPrice) => prevTotalPrice - (item.discounted_price * 1));
      localStorage.setItem(`cartCount_${index}`, JSON.stringify(updatedCounts[index]));
      return updatedCounts;
    });
  };

  return (
    <>
      <div className="add-to-card card mb-1">
        <div className="card-body d-flex">
          <div className="card-img d-flex justify-content-between align-items-center">
            <div className='border'>
              <img src={item.imgSrc} alt="card image" className='img-fluid' style={{ maxWidth: '100px' }} />

            </div>
            <div className='title'>
              <p className='text-muted'>{item.category} {index}</p>
              <p className='name'>{item.name} 1 kg</p>
              <p className='text-muted'>1 x 80.00</p>
            </div>
            <div className='d-flex amount'>
              <span onClick={handleDcrCount}>
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-dash border rounded-circle" viewBox="0 0 16 16">
                  <path d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8" />
                </svg>
              </span>
              <p className='mx-2 count'>{count}</p>
              <span onClick={handleIcrCount}>
                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" className="bi bi-plus border rounded-circle" viewBox="0 0 16 16">
                  <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4" />
                </svg>
              </span>
            </div>
            <div className='price'>
              <p>Rs. {discountedPrice}</p>
              <p className='text-success'>Save Rs. {savePrice}</p>
            </div>
            <div className='cross' onClick={handleDelete}>
              <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" fill="currentColor" className="bi bi-file-x" viewBox="0 0 16 16">
                <path fillRule="evenodd" d="M6.146 6.146a.5.5 0 0 1 .708 0L8 7.293l1.146-1.147a.5.5 0 1 1 .708.708L8.707 8l1.147 1.146a.5.5 0 0 1-.708.708L8 8.707 6.854 9.854a.5.5 0 0 1-.708-.708L7.293 8 6.146 6.854a.5.5 0 0 1 0-.708" />
              </svg>

            </div>

          </div>
        </div>
      </div>
    </>
  )
}

export default BasketItem;

Enter fullscreen mode Exit fullscreen mode

TotalPrice.js

import React from 'react';
import { useCart } from '../context/CartContext';

function TotalPrice() {
  const { totalPrice } = useCart();

  return (
    <>
        <div className='d-flex justify-content-end text-align-center align-items-center my-auto'>
        <div>
          <div className='d-flex justify-content-between mt-3'>
            <p>Total</p>
            <p>:</p>
            <p>{`Rs. ${totalPrice.toFixed(2)}`}</p>
          </div>
          <p className='line'></p>
          <div className='d-flex justify-content-end'>
            <button className='btn btn-dark'>Pay Now</button>
          </div>

        </div>
        </div>
    </>
  )
}

export default TotalPrice;

Enter fullscreen mode Exit fullscreen mode

context file CartContext.js

import React, { createContext, useContext, useEffect, useState } from 'react';

const CartContext = createContext();

export const CartProvider = ({ children }) => {
  const storedCartItems = JSON.parse(localStorage.getItem('cartItems')) || [];
  const storedPrice = JSON.parse(localStorage.getItem('cartItems_price'));
  const [cartItems, setCartItems] = useState(storedCartItems);
  let [totalPrice, setTotalPrice] = useState(storedPrice);

  const addToCart = (item, discounted_price) => {
    setCartItems((prevItems) => [...prevItems, item]);
    setTotalPrice(totalPrice + parseFloat(discounted_price));
  };

  const removeFromCart = (item, price) => {
    const updatedCartItems = cartItems.filter((cartItem) => cartItem.id !== item.id);
    setCartItems(updatedCartItems);

    setTotalPrice(totalPrice - price);
  };


  useEffect(() => {
    localStorage.setItem('cartItems', JSON.stringify(cartItems));
  }, [cartItems]);

  useEffect(() => {
    localStorage.setItem('cartItems_price', JSON.stringify(totalPrice));
  }, [totalPrice]);

  console.log('storedPrice', storedPrice)
  return (
    <CartContext.Provider value={{ cartItems, addToCart, removeFromCart,totalPrice, setTotalPrice }}>
      {children}
    </CartContext.Provider>
  );
};

export const useCart = () => {
  const context = useContext(CartContext);
  if (!context) {
    throw new Error('useCart must be used within a CartProvider');
  }
  return context;
};

Enter fullscreen mode Exit fullscreen mode

That's it.
Congratulations! You've successfully implemented the "Add to Cart" functionality in a React application.

Happy coding!🚀

💖 💪 🙅 🚩
rohitashsingh89
Rohitash Singh

Posted on January 22, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related