Build a Shopping Cart in Nodejs and React
Tags: react, javascript, webdev, beginners
Published: 2020-09-04 12:53:58

In this article we are going to build shopping cart frontend for our application. We will be using React for building our frontend.

You can check out [backend part built in Nodejs](https://blog.wrappixel.com/building-a-shopping-cart-in-nodejs/?ref=232).

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

To begin, we need to setup 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 .` 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).


## To The Main Work

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

We will continue by setting up our user interface for the application. You can get all our UI components from [WrapPixel's UI Kit](https://www.wrappixel.com/templates/wrapkit/?ref=232).

There are some online template store where you could get great free react dashboard like [WrapPixel](https://www.wrappixel.com/templates/category/react-templates/?ref=232) and [AdminMart](https://adminmart.com/templates/react/?ref=6).

We will add the bootstrap CDN into 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 service and views will be rendered in the pages for routing.

---

### Sponsored:

[![React](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6be3k0c5qa8udbdbqcsx.jpg)](https://adminmart.com/templates/react/?ref=6)

---

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 a http request to the backend to list all products and store 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 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



![Shop Listing](https://www.wrappixel.com/demos/images/shop-listing-with-vuej-vite.png)


Let’s head over to 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.

Notice the `increamentQty(id)` 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  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` 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);
        }
      }



![Shopping Cart](https://www.wrappixel.com/demos/images/cart-wrappixel-appliction.png)




## Exercise
- Implement the decrement feature
- Implement remove product from cart

After implementing this, Push your work to git and add the link in the comment section. Lets have some fun😁