Building an E-commerce Website with React and Commerce.js

This tutorial will guide you through the process of building an E-commerce website using React and Commerce.js. We will cover everything from setting up the development environment to implementing cart functionality and handling checkout and payments. By the end of this tutorial, you will have a fully functional E-commerce website built with React and Commerce.js.

building e commerce website react commercejs

Introduction

What is an E-commerce Website

An E-commerce website is an online platform where businesses can sell their products or services to customers. It allows customers to browse products, add them to a cart, and make payments securely. E-commerce websites have become increasingly popular as more and more people prefer to shop online.

Why use React and Commerce.js

React is a popular JavaScript library for building user interfaces. It allows developers to create reusable UI components and efficiently manage the state of their applications. React's component-based architecture makes it easy to build complex user interfaces and keep the codebase organized.

Commerce.js is a powerful API-first e-commerce platform that provides all the necessary tools and functionality to build an E-commerce website. It handles everything from product management and inventory tracking to payment processing and order management. With Commerce.js, developers can focus on building the UI and business logic of their E-commerce websites without worrying about the backend infrastructure.

Setting up the Development Environment

Before we can start building our E-commerce website, we need to set up our development environment. We will need to install Node.js and npm, create a new React project, and install Commerce.js.

Installing Node.js and npm

Node.js is a JavaScript runtime that allows us to run JavaScript code outside of the web browser. npm (Node Package Manager) is a package manager for Node.js that allows us to install and manage dependencies for our projects.

To install Node.js and npm, follow these steps:

  1. Visit the official Node.js website (https://nodejs.org) and download the latest LTS version of Node.js for your operating system.
  2. Run the installer and follow the instructions to install Node.js.
  3. Open a terminal or command prompt and type node -v to check if Node.js is installed correctly. You should see the version number of Node.js.
  4. Type npm -v to check if npm is installed correctly. You should see the version number of npm.

Creating a new React project

Now that we have Node.js and npm installed, we can create a new React project. We will use the create-react-app command-line tool to generate a new React project with the basic project structure and configuration.

To create a new React project, follow these steps:

  1. Open a terminal or command prompt and navigate to the directory where you want to create your project.
  2. Run the following command to create a new React project named "ecommerce-website":
npx create-react-app ecommerce-website
  1. Wait for the project to be created. This may take a few minutes depending on your internet connection.
  2. Once the project is created, navigate to the project directory:
cd ecommerce-website

Installing Commerce.js

With our React project set up, we can now install Commerce.js. Commerce.js provides a JavaScript SDK that allows us to interact with the Commerce.js API and easily manage our E-commerce website's data.

To install Commerce.js, follow these steps:

  1. Open a terminal or command prompt and navigate to your React project directory.
  2. Run the following command to install Commerce.js:
npm install @chec/commerce.js
  1. Wait for the dependencies to be installed. This may take a few minutes.
  2. Once the installation is complete, we can start building our E-commerce website.

Creating the Layout and Navigation

In this section, we will set up the project structure and create the layout and navigation components for our E-commerce website.

Setting up the project structure

Before we start building our components, let's set up the project structure. In the src directory of your React project, create the following directories:

  • components: This directory will contain all our reusable UI components.
  • pages: This directory will contain the main pages of our website.

Inside the components directory, create a new file named Header.js and add the following code:

import React from 'react';

const Header = () => {
  return (
    <header>
      <h1>E-commerce Website</h1>
    </header>
  );
};

export default Header;

This is a simple header component that displays the title of our website. We will import and use this component in our layout component.

Inside the components directory, create another file named Navigation.js and add the following code:

import React from 'react';

const Navigation = () => {
  return (
    <nav>
      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/categories">Categories</a></li>
        <li><a href="/cart">Cart</a></li>
      </ul>
    </nav>
  );
};

export default Navigation;

This is a simple navigation component that displays the links to the home page, categories page, and cart page of our website. We will also import and use this component in our layout component.

Creating the layout component

Inside the components directory, create a new file named Layout.js and add the following code:

import React from 'react';
import Header from './Header';
import Navigation from './Navigation';

const Layout = ({ children }) => {
  return (
    <div>
      <Header />
      <Navigation />
      {children}
    </div>
  );
};

export default Layout;

This is our layout component that displays the header and navigation components and renders the content passed as the children prop. We will wrap our main pages with this layout component to ensure a consistent layout across all pages.

Managing Products and Categories

In this section, we will fetch products from Commerce.js, display them on the homepage, and create category pages to display products based on their categories.

Fetching products from Commerce.js

To fetch products from Commerce.js, we will need to create a new instance of the Commerce class provided by the Commerce.js SDK and call the products.list() method.

Inside the pages directory, create a new file named HomePage.js and add the following code:

import React, { useEffect, useState } from 'react';
import { Commerce } from '@chec/commerce.js';

const commerce = new Commerce(process.env.REACT_APP_CHEC_PUBLIC_KEY);

const HomePage = () => {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    const fetchProducts = async () => {
      try {
        const { data } = await commerce.products.list();
        setProducts(data);
      } catch (error) {
        console.error(error);
      }
    };

    fetchProducts();
  }, []);

  return (
    <div>
      <h2>Featured Products</h2>
      <ul>
        {products.map((product) => (
          <li key={product.id}>
            <img src={product.media.source} alt={product.name} />
            <h3>{product.name}</h3>
            <p>{product.price.formatted_with_symbol}</p>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default HomePage;

This is our homepage component that fetches the list of products from Commerce.js and displays them as a list. We use the useState and useEffect hooks provided by React to manage the state and perform the API request.

Creating category pages

To create category pages, we will need to fetch the list of categories from Commerce.js and filter the products based on their categories.

Inside the pages directory, create a new file named CategoryPage.js and add the following code:

import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { Commerce } from '@chec/commerce.js';

const commerce = new Commerce(process.env.REACT_APP_CHEC_PUBLIC_KEY);

const CategoryPage = () => {
  const { categoryId } = useParams();
  const [products, setProducts] = useState([]);

  useEffect(() => {
    const fetchProducts = async () => {
      try {
        const { data } = await commerce.products.list({ category: [categoryId] });
        setProducts(data);
      } catch (error) {
        console.error(error);
      }
    };

    fetchProducts();
  }, [categoryId]);

  return (
    <div>
      <h2>Category: {categoryId}</h2>
      <ul>
        {products.map((product) => (
          <li key={product.id}>
            <img src={product.media.source} alt={product.name} />
            <h3>{product.name}</h3>
            <p>{product.price.formatted_with_symbol}</p>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default CategoryPage;

This is our category page component that fetches the list of products filtered by the specified category from Commerce.js and displays them as a list. We use the useParams hook provided by React Router to get the categoryId parameter from the URL.

Implementing Cart Functionality

In this section, we will implement cart functionality, which includes adding products to the cart, updating the cart, and displaying the cart.

Adding products to the cart

To add products to the cart, we will need to create a new instance of the Commerce class provided by the Commerce.js SDK and call the cart.add() method.

Inside the components directory, create a new file named ProductCard.js and add the following code:

import React from 'react';
import { Commerce } from '@chec/commerce.js';

const commerce = new Commerce(process.env.REACT_APP_CHEC_PUBLIC_KEY);

const ProductCard = ({ product }) => {
  const handleAddToCart = async () => {
    try {
      await commerce.cart.add(product.id, 1);
      alert('Product added to cart');
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <div>
      <img src={product.media.source} alt={product.name} />
      <h3>{product.name}</h3>
      <p>{product.price.formatted_with_symbol}</p>
      <button onClick={handleAddToCart}>Add to Cart</button>
    </div>
  );
};

export default ProductCard;

This is our product card component that displays the product image, name, price, and an "Add to Cart" button. When the button is clicked, we call the cart.add() method of the Commerce.js SDK to add the product to the cart.

Updating the cart

To update the cart, we will need to create a new instance of the Commerce class provided by the Commerce.js SDK and call the cart.update() method.

Inside the pages directory, open the HomePage.js file and modify the code as follows:

import React, { useEffect, useState } from 'react';
import { Commerce } from '@chec/commerce.js';

const commerce = new Commerce(process.env.REACT_APP_CHEC_PUBLIC_KEY);

const HomePage = () => {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    const fetchProducts = async () => {
      try {
        const { data } = await commerce.products.list();
        setProducts(data);
      } catch (error) {
        console.error(error);
      }
    };

    fetchProducts();
  }, []);

  const handleUpdateCart = async () => {
    try {
      const { data } = await commerce.cart.update('cart_id', { quantity: 2 });
      console.log(data);
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <div>
      <h2>Featured Products</h2>
      <button onClick={handleUpdateCart}>Update Cart</button>
      <ul>
        {products.map((product) => (
          <li key={product.id}>
            <img src={product.media.source} alt={product.name} />
            <h3>{product.name}</h3>
            <p>{product.price.formatted_with_symbol}</p>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default HomePage;

This is an updated version of our homepage component that includes a button to update the cart. When the button is clicked, we call the cart.update() method of the Commerce.js SDK to update the cart by changing the quantity of a product.

Displaying the cart

To display the cart, we will need to create a new instance of the Commerce class provided by the Commerce.js SDK and call the cart.retrieve() method.

Inside the pages directory, open the HomePage.js file and modify the code as follows:

import React, { useEffect, useState } from 'react';
import { Commerce } from '@chec/commerce.js';

const commerce = new Commerce(process.env.REACT_APP_CHEC_PUBLIC_KEY);

const HomePage = () => {
  const [products, setProducts] = useState([]);
  const [cart, setCart] = useState(null);

  useEffect(() => {
    const fetchProducts = async () => {
      try {
        const { data } = await commerce.products.list();
        setProducts(data);
      } catch (error) {
        console.error(error);
      }
    };

    const fetchCart = async () => {
      try {
        const { data } = await commerce.cart.retrieve();
        setCart(data);
      } catch (error) {
        console.error(error);
      }
    };

    fetchProducts();
    fetchCart();
  }, []);

  const handleUpdateCart = async () => {
    try {
      const { data } = await commerce.cart.update('cart_id', { quantity: 2 });
      console.log(data);
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <div>
      <h2>Featured Products</h2>
      <button onClick={handleUpdateCart}>Update Cart</button>
      {cart && (
        <div>
          <h3>Cart</h3>
          <ul>
            {cart.line_items.map((lineItem) => (
              <li key={lineItem.id}>
                <img src={lineItem.media.source} alt={lineItem.name} />
                <h4>{lineItem.name}</h4>
                <p>Price: {lineItem.price.formatted_with_symbol}</p>
                <p>Quantity: {lineItem.quantity}</p>
              </li>
            ))}
          </ul>
        </div>
      )}
      <ul>
        {products.map((product) => (
          <li key={product.id}>
            <img src={product.media.source} alt={product.name} />
            <h3>{product.name}</h3>
            <p>{product.price.formatted_with_symbol}</p>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default HomePage;

This is an updated version of our homepage component that includes the cart section. We use the useState hook to manage the state of the cart and call the cart.retrieve() method of the Commerce.js SDK to retrieve the cart data.

Handling Checkout and Payments

In this section, we will create a checkout form, integrate with a payment gateway, and handle successful and failed payments.

Creating a checkout form

To create a checkout form, we will need to create a new instance of the Commerce class provided by the Commerce.js SDK and call the checkout.generateToken() method.

Inside the pages directory, create a new file named CheckoutPage.js and add the following code:

import React, { useEffect, useState } from 'react';
import { Commerce } from '@chec/commerce.js';

const commerce = new Commerce(process.env.REACT_APP_CHEC_PUBLIC_KEY);

const CheckoutPage = () => {
  const [checkoutToken, setCheckoutToken] = useState(null);

  useEffect(() => {
    const generateCheckoutToken = async () => {
      try {
        const { data } = await commerce.checkout.generateToken('cart_id', { type: 'cart' });
        setCheckoutToken(data);
      } catch (error) {
        console.error(error);
      }
    };

    generateCheckoutToken();
  }, []);

  return (
    <div>
      {checkoutToken && (
        <form>
          <h2>Checkout</h2>
          <input type="text" placeholder="First Name" />
          <input type="text" placeholder="Last Name" />
          <input type="email" placeholder="Email" />
          <input type="text" placeholder="Address" />
          <input type="text" placeholder="City" />
          <input type="text" placeholder="Postal Code" />
          <button type="submit">Place Order</button>
        </form>
      )}
    </div>
  );
};

export default CheckoutPage;

This is our checkout page component that generates a checkout token using the checkout.generateToken() method of the Commerce.js SDK and displays a checkout form. We use the useState hook to manage the state of the checkout token.

Integrating with a payment gateway

To integrate with a payment gateway, we will need to create a new instance of the Commerce class provided by the Commerce.js SDK and call the checkout.capture() method.

Inside the pages directory, open the CheckoutPage.js file and modify the code as follows:

import React, { useEffect, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { Commerce } from '@chec/commerce.js';

const commerce = new Commerce(process.env.REACT_APP_CHEC_PUBLIC_KEY);

const CheckoutPage = () => {
  const history = useHistory();
  const [checkoutToken, setCheckoutToken] = useState(null);

  useEffect(() => {
    const generateCheckoutToken = async () => {
      try {
        const { data } = await commerce.checkout.generateToken('cart_id', { type: 'cart' });
        setCheckoutToken(data);
      } catch (error) {
        console.error(error);
      }
    };

    generateCheckoutToken();
  }, []);

  const handlePlaceOrder = async (event) => {
    event.preventDefault();

    try {
      const { data } = await commerce.checkout.capture('checkout_token', {
        payment: {
          gateway: 'stripe',
          card: {
            number: '4242 4242 4242 4242',
            expiry_month: '01',
            expiry_year: '2023',
            cvc: '123',
            postal_zip_code: '12345',
          },
        },
      });

      console.log(data);
      history.push('/success');
    } catch (error) {
      console.error(error);
      history.push('/failed');
    }
  };

  return (
    <div>
      {checkoutToken && (
        <form onSubmit={handlePlaceOrder}>
          <h2>Checkout</h2>
          <input type="text" placeholder="First Name" />
          <input type="text" placeholder="Last Name" />
          <input type="email" placeholder="Email" />
          <input type="text" placeholder="Address" />
          <input type="text" placeholder="City" />
          <input type="text" placeholder="Postal Code" />
          <button type="submit">Place Order</button>
        </form>
      )}
    </div>
  );
};

export default CheckoutPage;

This is an updated version of our checkout page component that includes the integration with a payment gateway. We use the useHistory hook provided by React Router to navigate to the success or failed page based on the result of the payment.

Handling successful and failed payments

To handle successful and failed payments, we will navigate to a success or failed page based on the result of the payment.

Inside the pages directory, create two new files named SuccessPage.js and FailedPage.js and add the following code to each file:

SuccessPage.js:

import React from 'react';

const SuccessPage = () => {
  return (
    <div>
      <h2>Payment Successful</h2>
      <p>Thank you for your order!</p>
    </div>
  );
};

export default SuccessPage;

FailedPage.js:

import React from 'react';

const FailedPage = () => {
  return (
    <div>
      <h2>Payment Failed</h2>
      <p>Sorry, there was an error processing your payment.</p>
    </div>
  );
};

export default FailedPage;

These are our success and failed page components that display a message based on the result of the payment.

Conclusion

In this tutorial, we have learned how to build an E-commerce website with React and Commerce.js. We started by setting up the development environment and installing the necessary dependencies. Then, we created the layout and navigation components, fetched products from Commerce.js, and displayed them on the homepage and category pages. We also implemented cart functionality, including adding products to the cart, updating the cart, and displaying the cart. Finally, we handled checkout and payments by creating a checkout form, integrating with a payment gateway, and handling successful and failed payments.

By following this tutorial, you should now have a solid understanding of how to build an E-commerce website using React and Commerce.js. Feel free to customize and extend the functionality of your website to meet your specific requirements. Happy coding!