In this article, we will give you a NodeJs tutorial that how we are going to build a shopping cart frontend with React for our application. This will be a simple tutorial on React Shopping Cart.

I hope you have read our article How to Build a Shopping Cart in NodeJs? earlier. If not, then you can get guidance in easy steps.

As far as we can, this will be minimal for a full understanding of the main functionality.

To begin, we need to set up our React application using create-react-app.

npx create-react-app shopping-cart
cd shopping-cart
code .
npm start

You might need to install the react CLI first on your local machine if you haven’t before.

The code . the command opens the project in visual studio code.

We can now discard the things we don’t need in App.js, and also get rid of the files (App.css and index.css).

React Shopping Cart with NodeJs

First, we create a components folder; this houses our reusable components, for example, Navbar.

We will continue by setting up our user interface (UI) for the application. You can get all UI components from WrapPixel’s UI Kit. WrapPixel is an online template store where you could get great Free React Dashboard and React Bootstrap Templates.

We will add the bootstrap CDN to our root index.html file inside the public directory.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="theme-color" content="#000000" />
  <meta name="description" content="Web site created using create-react-app" />
  <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
    integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
  <title>Shopping cart</title>
</head>
<body>
  <noscript>You need to enable JavaScript to run this app.</noscript>
  <div id="root"></div>
</body>
</html>

Then we add a Navbar.js file to the components folder. This is where we will handle our routing.

import React from "react"
import {
  Link
} from "react-router-dom"
export const Navbar = () => {
  return ( <
    nav className = "navbar navbar-expand-lg navbar-light bg-info" >
    <
    div className = "container" >
    <
    Link to = "/"
    className = "navbar-brand" > Vue Cart < /Link>
    <
    div className = "collapse navbar-collapse justify-content-end"
    id = "navbarNav" >
    <
    ul className = "navbar-nav" >
    <
    li className = "nav-item active" >
    <
    Link to = "/"
    className = "nav-link" > Home < /Link> < /
    li > <
    li className = "nav-item" >
    <
    Link to = "/cart"
    className = "nav-link" > Cart < /Link> < /
    li > <
    /ul> < /
    div > < /div> < /
    nav >
  )
}

Remember that we are using react-router-dom to route pages, so we need to add Navbar below our switch, as seen below ‘App.js’

import React from "react"
import { Switch } from "react-router-dom"
import { Navbar } from "./components/Navbar"

import "./App.css"
function App() {
  return (
    <div className='App'>
      <Navbar />
      <Switch>
        // Our pages will go here
      </Switch>
    </div>
  )
}
export default App

Secondly, we create a page folder. This folder houses our pages(product and cart page), all our services and views will be rendered in the pages for routing.

Let’s create a simple Product.js

import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
export const Products = () => {
  const [products, setProducts] = useState([]);
  const [hasError, setError] = useState(false);
  async function fetchData() {
    const res = await fetch("http://localhost:4000/product");
    res
      .json()
      .then((res) => {
        console.log(res.data);
        setProducts(res.data);
      })
      .catch((error) => {
        setError(error);
      });
  }
  async function addToCart(id, quantity) {
    try {
      const response = await fetch("http://localhost:4000/cart", {
        method: "POST",
        body: JSON.stringify({
          productId: id,
          quantity: quantity,
        }),
        headers: {
          "Content-type": "application/json; charset=UTF-8",
        },
      });
      let data = await response.json();
      alert("Item Added To Cart");
      console.log(data);
    } catch (err) {
      alert("Something Went Wrong");
      console.log(err);
    }
  }
  useEffect(() => {
    fetchData();
  }, []);
  console.log(products);
  return (
    <main>
      <section>
        <div className="banner-innerpage">
          <div className="container">
            <div className="row justify-content-center">
              <div className="col-md-6 align-self-center text-center">
                <h1 className="title">Shop listing</h1>
                <h6 className="subtitle op-8">
                  We are small team of creative people working together
                </h6>
              </div>
            </div>
          </div>
        </div>
      </section>
      <section>
        <div className="spacer">
          <div className="container">
            <div className="row mt-5">
              <div className="col-lg-9">
                <div className="row shop-listing">
                  {products.map((product, i) => (
                    <div className="col-lg-4">
                      <div className="card shop-hover border-0">
                        <img
                          src={"http://localhost:4000/" + product.image}
                          alt="wrapkit"
                          className="img-fluid"
                        />
                        <div className="card-img-overlay align-items-center">
                          <button
                            onClick={(e) => addToCart(product._id, 1)}
                            className="btn btn-md btn-info"
                          >
                            Add to cart
                          </button>
                        </div>
                      </div>
                      <div className="card border-0">
                        <h6>
                          <a href="#" className="link">
                            {product.name}{" "}
                          </a>
                        </h6>
                        <h6 className="subtitle">by Wisdom</h6>
                        <h5 className="font-medium m-b-30">
                          $195 /{" "}
                          <del className="text-muted line-through">$225</del>
                        </h5>
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>
    </main>
  );
};

Noticed the fetchData function? We make an HTTP request to the backend to list all products and store them in the variable products (we are using React hooks, remember).

Since we have it as an array now, we loop through it to display as seen on line 64.

We will also need to add items to the cart, which will be an async method making a request to the backend with its parameters passed to it. This is a very important feature as well.

The addToCart is defined on line 18:

  async function addToCart(id, quantity) {
    try {
      const response = await fetch("http://localhost:4000/cart", {
        method: "POST",
        body: JSON.stringify({
          productId: id,
          quantity: quantity,
        }),
        headers: {
          "Content-type": "application/json; charset=UTF-8",
        },
      })
      let data = await response.json()
      console.log(data)
    } catch (err) {
      console.log(err)
    }
  }

After that, We add the event listener to the button to call the addToCart button

 <button
                            onClick={(e) => addToCart(product._id, 1)}
                            className="btn btn-md btn-info"
                          >
                            Add to cart
                          </button>

Here, we pass the id of the product and a default quantity as 1.

Then add to our App.js once again, as a page.

import React from "react"
import { Switch, Route } from "react-router-dom"
import { Products } from "./pages/product"

import { Navbar } from "./components/Navbar"

import "./App.css"
function App() {
  return (
    <div className='App'>
      <Navbar />
      <Switch>
        <Route exact path='/' component={Products} />
      </Switch>
    </div>
  )
}
export default App
react shopping cart

Let’s head over to the cart page and add our simple UI.

We then add a method to fetch a list of our cart items from the backend. Notice the fetchCart method below. Doing as pleased.

If you are not familiar with react hooks, you could always look it up or better still use the component-based.

import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import "./cart.css";
export const Cart = (props) => {
  const [carts, setCarts] = useState([]);
  const [payload, setPayloader] = useState({});
  const [hasError, setError] = useState(false);
  async function fetchCart() {
    const res = await fetch("http://localhost:4000/cart");
    res
      .json()
      .then((res) => {
        console.log(res.data.items);
        setCarts(res.data.items);
        setPayloader(res.data);
      })
      .catch((error) => {
        setError(error);
      });
  }
  async function increaseQty(id) {
    try {
      const res = await fetch("http://localhost:4000/cart", {
        method: "POST",
        body: JSON.stringify({
          productId: id,
          quantity: 1,
        }),
        headers: {
          "Content-type": "application/json; charset=UTF-8",
        },
      });
      console.log(res);
      fetchCart();
      alert("Item Increamented");
    } catch (err) {
      console.log(err);
    }
  }
  async function emptyCart() {
    try {
      const res = await fetch("http://localhost:4000/cart/empty-cart", {
        method: "DELETE",
      });
      await res.json();
      fetchCart();
      props.history.push("/");
    } catch (err) {
      console.log(err);
    }
  }
  useEffect(() => {
    fetchCart();
  }, []);
  return (
    <main>
      <section>
        <div className="banner-innerpage">
          <div className="container">
            <div className="row justify-content-center">
              <div className="col-md-6 align-self-center text-center">
                <h1 className="title">Cart Listing</h1>
                <h6 className="subtitle op-8">
                  We are small team of creative people working together
                </h6>
              </div>
            </div>
          </div>
        </div>
      </section>
      <section>
        <div className="spacer">
          <div className="container">
            <div className="row mt-5">
              <div className="col-lg-9">
                <div className="row shop-listing">
                  <table className="table shop-table">
                    <tr>
                      <th className="b-0">Name</th>
                      <th className="b-0">Price</th>
                      <th className="b-0">Quantity</th>
                      <th className="b-0 text-right">Total Price</th>
                    </tr>
                    {carts.map((item, i) => (
                      <tr>
                        <td>{item.productId.name}</td>
                        <td>{item.productId.price}</td>
                        <td>
                          <button
                            onClick={(e) => increaseQty(item.productId._id)}
                            className="btn btn-primary btn-sm"
                          >
                            +
                          </button>
                          {item.quantity}
                          <button className="btn btn-primary btn-sm">-</button>
                        </td>
                        <td className="text-right">
                          <h5 className="font-medium m-b-30">{item.total}</h5>
                        </td>
                      </tr>
                    ))}
                    <tr>
                      <td colspan="3" align="right">
                        Subtotal :{payload.subTotal}
                      </td>
                      <td colspan="4" align="right">
                        <button
                          className="btn btn-danger"
                          onClick={(e) => emptyCart()}
                        >
                          Empty cart
                        </button>
                      </td>
                    </tr>
                  </table>
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>
    </main>
  );
};

We can then loop through the array(cart) and modify it.

Notice the increamentQty(id) the method which takes the product id as a parameter and then set the quantity to one as default as we are updating the quantity by one.

 async function increaseQty(id) {
    try {
      const res = await fetch("http://localhost:4000/cart", {
        method: "POST",
        body: JSON.stringify({
          productId: id,
          quantity: 1,
        }),
        headers: {
          "Content-type": "application/json; charset=UTF-8",
        },
      });
      console.log(res);
      fetchCart();
      alert("Item increamented");
    } catch (err) {
      console.log(err);
    }
  }

After doing that we added a click event to our button to trigger the method:

  <button
                            onClick={(e) => increaseQty(item.productId._id)}
                            className="btn btn-primary btn-sm"
                          >
                            +
                          </button>

Clicking on the button will increment the quantity of the item.

We then define an emptyCart the method as well to delete all items currently in the cart. See below;

 async function emptyCart() {
    try {
      const res = await fetch("http://localhost:4000/cart/empty-cart", {
        method: "DELETE",
      });
      await res.json();
      fetchCart();
      props.history.push("/");
    } catch (err) {
      console.log(err);
    }
  }
Node js tutorial shopping cart

So we have seen React Shopping Cart with NodeJs. Now let’s practice some exercises.

Exercise

  • Implement the decrement feature
  • Implement remove a product from the cart

After implementing this, Push your work to git and add the link in the comment section. I think you will like our node js tutorial to build react shopping cart. Do let us know. Let’s have some fun with these exercises.

Conclusion

We have learned to build a shopping cart using NodeJs and React. I hope you found it useful and helpful for your practice or current project. Building a shopping cart using other platforms or technologies is also available in our below articles:

How to Build a Shopping Cart in NodeJs and Vue Vite?

How to Build a Shopping Cart in NodeJs and Angular 10?

How to Build a Shopping Cart in NodeJs?

Hope you enjoyed learning and doing exercises in building a react shopping cart with NodeJs. Keep Coding.