Build a Simple Next.js E-commerce Cart with State Management

Written by

in

In the ever-evolving landscape of web development, e-commerce remains a dominant force. Building a functional e-commerce cart is a fundamental skill for any aspiring web developer. This article will guide you through creating a simple, yet effective, e-commerce cart using Next.js, a popular React framework, and provide clear explanations and step-by-step instructions. We’ll focus on state management to ensure your cart behaves predictably and reliably. This project is designed for beginners to intermediate developers, and will provide a solid foundation for more complex e-commerce projects.

Why Build an E-commerce Cart?

An e-commerce cart is more than just a place to store items; it’s a critical component of the user experience. A well-designed cart enhances user satisfaction, encourages purchases, and contributes to the overall success of an online store. Understanding how to build a cart provides valuable insights into state management, component interaction, and data handling, core concepts in modern web development. This knowledge is transferable to a wide range of web applications beyond e-commerce.

Prerequisites

Before we dive in, ensure you have the following:

  • A basic understanding of HTML, CSS, and JavaScript.
  • Node.js and npm (or yarn) installed on your system.
  • A code editor (e.g., VS Code, Sublime Text).
  • A basic understanding of React (components, props, state).

Setting Up Your Next.js Project

Let’s start by creating a new Next.js project. Open your terminal and run the following command:

npx create-next-app my-ecommerce-cart
cd my-ecommerce-cart

This command creates a new Next.js project named ‘my-ecommerce-cart’. Navigate into the project directory using ‘cd my-ecommerce-cart’. Now, let’s install some dependencies we’ll need for our cart functionality. We will use a simple state management solution, and we will install a library to help us with the cart’s styling.

npm install react-icons styled-components

Project Structure

A well-organized project structure makes development and maintenance easier. Here’s a suggested structure for our project:

my-ecommerce-cart/
├── components/
│   ├── ProductCard.js
│   ├── CartItem.js
│   └── Cart.js
├── pages/
│   ├── index.js
│   └── _app.js
├── styles/
│   └── global.css
├── public/
│   └── ... (images, etc.)
└── package.json

This structure separates components (ProductCard, CartItem, Cart) from the pages (index.js), allowing for modular and reusable code. The styles directory will contain our global styles.

Creating the ProductCard Component

The ProductCard component will display individual product information. Create a file named ProductCard.js inside the components directory. Add the following code:

import React from 'react';
import styled from 'styled-components';
import { FaShoppingCart } from 'react-icons/fa';

const CardContainer = styled.div`
  border: 1px solid #ccc;
  padding: 1rem;
  margin-bottom: 1rem;
  border-radius: 8px;
  text-align: center;
`;

const Image = styled.img`
  max-width: 100%;
  height: 150px;
  object-fit: contain;
  margin-bottom: 1rem;
`;

const Button = styled.button`
  background-color: #0070f3;
  color: white;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.2s ease;

  &:hover {
    background-color: #0056b3;
  }
`;

const ProductCard = ({ product, onAddToCart }) => {
  return (
    
      
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <Button> onAddToCart(product)}>
         Add to Cart
      </Button>
    
  );
};

export default ProductCard;

This component displays a product’s image, name, and price, along with an ‘Add to Cart’ button. The styling is handled using styled-components, a CSS-in-JS library. The FaShoppingCart icon is imported from the react-icons library.

Creating the CartItem Component

The CartItem component will represent a single item within the shopping cart. Create a file named CartItem.js inside the components directory. Add the following code:

import React from 'react';
import styled from 'styled-components';
import { FaTrash } from 'react-icons/fa';

const ItemContainer = styled.div`
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.5rem 0;
  border-bottom: 1px solid #eee;
`;

const Image = styled.img`
  width: 50px;
  height: 50px;
  object-fit: cover;
  margin-right: 1rem;
`;

const ItemDetails = styled.div`
  flex-grow: 1;
`;

const RemoveButton = styled.button`
  background-color: #dc3545;
  color: white;
  border: none;
  padding: 0.25rem 0.5rem;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.2s ease;

  &:hover {
    background-color: #c82333;
  }
`;

const CartItem = ({ item, onRemoveFromCart }) => {
  return (
    
      <div style="{{">
        
        
          <p>{item.name}</p>
          <p>Price: ${item.price}</p>
          <p>Quantity: {item.quantity}</p>
        
      </div>
       onRemoveFromCart(item.id)}>
        
      
    
  );
};

export default CartItem;

This component displays the product image, name, price, and quantity, and includes a ‘Remove’ button. The styling, again, is done using styled-components, and a trash icon is imported.

Creating the Cart Component

The Cart component will render the cart items and the total price. Create a file named Cart.js inside the components directory. Add the following code:

import React from 'react';
import styled from 'styled-components';
import CartItem from './CartItem';

const CartContainer = styled.div`
  border: 1px solid #ccc;
  padding: 1rem;
  border-radius: 8px;
  width: 300px;
  position: fixed;
  top: 20px;
  right: 20px;
  background-color: white;
  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
`;

const CartTitle = styled.h2`
  margin-bottom: 1rem;
  text-align: center;
`;

const Total = styled.p`
  font-weight: bold;
  margin-top: 1rem;
  text-align: right;
`;

const Cart = ({ cartItems, onRemoveFromCart }) => {
  const totalPrice = cartItems.reduce((acc, item) => acc + item.price * item.quantity, 0);

  return (
    
      Your Cart
      {cartItems.length === 0 ? (
        <p>Your cart is empty.</p>
      ) : (
        cartItems.map((item) => (
          
        ))
      )}
      Total: ${totalPrice.toFixed(2)}
    
  );
};

export default Cart;

This component displays the cart title, cart items (using the CartItem component), and the total price. It also handles the display of an empty cart message.

Building the Main Page (index.js)

Now, let’s build the main page, index.js, which will display the product cards and the cart. Replace the content of pages/index.js with the following code:

import React, { useState } from 'react';
import styled from 'styled-components';
import ProductCard from '../components/ProductCard';
import Cart from '../components/Cart';

const Container = styled.div`
  display: flex;
  justify-content: space-around;
  padding: 2rem;
`;

const ProductList = styled.div`
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1rem;
  width: 70%;
`;

const productsData = [
  {
    id: 1,
    name: 'Product 1',
    image: '/product1.jpg',
    price: 25,
  },
  {
    id: 2,
    name: 'Product 2',
    image: '/product2.jpg',
    price: 35,
  },
  {
    id: 3,
    name: 'Product 3',
    image: '/product3.jpg',
    price: 45,
  },
  {
    id: 4,
    name: 'Product 4',
    image: '/product4.jpg',
    price: 55,
  },
  {
    id: 5,
    name: 'Product 5',
    image: '/product5.jpg',
    price: 65,
  },
];

const Index = () => {
  const [cartItems, setCartItems] = useState([]);

  const handleAddToCart = (product) => {
    const existingItemIndex = cartItems.findIndex((item) => item.id === product.id);

    if (existingItemIndex !== -1) {
      const updatedCartItems = [...cartItems];
      updatedCartItems[existingItemIndex].quantity += 1;
      setCartItems(updatedCartItems);
    } else {
      setCartItems([...cartItems, { ...product, quantity: 1 }]);
    }
  };

  const handleRemoveFromCart = (productId) => {
    const updatedCartItems = cartItems.filter((item) => item.id !== productId);
    setCartItems(updatedCartItems);
  };

  return (
    
      
        {productsData.map((product) => (
          
        ))}
      
      
    
  );
};

export default Index;

This page imports the ProductCard and Cart components. It also defines an array of sample product data (productsData) and manages the cart state using the useState hook. The handleAddToCart function adds products to the cart or increments the quantity if the product already exists. The handleRemoveFromCart function removes items from the cart.

Styling the Application

To style the application, add the following CSS to styles/global.css:

body {
  font-family: sans-serif;
  margin: 0;
  padding: 0;
  background-color: #f4f4f4;
}

* {
  box-sizing: border-box;
}

This CSS sets the basic styling for the body and ensures that all elements use the box-sizing property.

Adding Product Images

To display product images, you’ll need to add image files to the public directory. Create the following images (or use your own):

  • public/product1.jpg
  • public/product2.jpg
  • public/product3.jpg
  • public/product4.jpg
  • public/product5.jpg

You can use placeholder images or real product images.

Running the Application

Now, run your application in the terminal:

npm run dev

This command starts the Next.js development server. Open your browser and go to http://localhost:3000. You should see the product cards and an empty cart. Clicking the ‘Add to Cart’ buttons should add items to the cart, and the cart should update accordingly.

Common Mistakes and How to Fix Them

Here are some common mistakes and how to avoid them:

  • Incorrect Path for Images: Ensure the image paths in ProductCard.js are correct relative to the public directory. Double-check the file names and paths.
  • State Not Updating: If the cart isn’t updating, make sure you’re correctly updating the cartItems state using the setCartItems function. Also, ensure you’re using the correct dependency array in useEffect hooks (if you used them).
  • Missing Dependencies: If you encounter errors about missing modules, make sure you’ve installed all the necessary dependencies using npm install.
  • Incorrect Component Imports: Ensure that you are importing components correctly. For example, check that you have the correct file paths for the ProductCard and Cart components.
  • Styling Issues: If the styling isn’t applied correctly, verify that you’ve installed styled-components and that you’ve correctly imported and used the styled components. Double-check your CSS syntax.

Enhancements and Next Steps

This is a basic e-commerce cart. Here are some ways to enhance it:

  • Persist Cart Data: Use local storage or cookies to persist the cart data even after the user closes the browser. This ensures that the cart items are preserved.
  • Add Product Details Page: Create a detailed product page that displays more information about each product.
  • Implement Checkout: Integrate a payment gateway (e.g., Stripe, PayPal) to allow users to complete purchases.
  • Add Quantity Input: Allow users to specify the quantity of each product they want to add to their cart.
  • Use a State Management Library: For larger applications, consider using a dedicated state management library like Redux, Zustand, or Recoil to manage the cart state.
  • Improve UI/UX: Enhance the user interface and user experience with better styling, animations, and responsiveness. Consider using a UI library like Material UI, Ant Design, or Chakra UI to speed up development.

Key Takeaways

Building an e-commerce cart is a valuable learning experience. You have learned how to create a basic e-commerce cart using Next.js, a popular React framework. You’ve also learned about state management, component interaction, and data handling. By following these steps, you’ve created a functional cart that allows users to add and remove items. This project serves as a foundation for building more complex e-commerce applications. Remember to continually practice and experiment to solidify your understanding and expand your skills. E-commerce is a continually evolving field, with new technologies and best practices emerging regularly. Staying informed and adaptable is key to success.

Now, go forth and build your own e-commerce empires, one cart at a time!