How to make data inside of cart become Persistent - NextJS

Updated at: 1 April 2023Deepak Painkra

In this article, I will be teaching you how to create a card state for products using NextJS,

When we click the button, it will get added to the cart. And when we press to remove button, it gets removed from the cart, and it has an increment & decrement function.

Note:- I'm expecting that you have already created your NavBar to follow this tutoring, and I have shared all these codes in one place for clarification.

Creating NextJS App

First, let's create a NextJS app by running this command

npx create-next-app@latest

We are implementing this feature on every page. So that those users will be able to see their items on every page, So let's open up the app.js file

import Footer from "@/components/Footer";
import Navbar from "@/components/Navbar";
import "@/styles/globals.css";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

export default function App({ Component, pageProps }) {
  const [cart, setCart] = useState({});
  const [subTotal, setSubTotal] = useState(0);
  const router = useRouter();
}

And will create two constants first cart and the second subTotal. The cart value is an empty object because we are setting its value, and the subTotal will be zero initially, which means the number of an item.

Let's create a first method addToCart with the arrow function, then after, we will add all these items such as price, qty, name, size, variant

const addToCart = (itemCode, qty, price, name, size, variant) => {
    let newCart = cart;
    toast.success("Item added successfully!", {
      position: "top-center",
      autoClose: 1500,
      hideProgressBar: true,
      closeOnClick: true,
      pauseOnHover: true,
      draggable: true,
      progress: undefined,
      theme: "light",
    });
    if (itemCode in cart) {
      newCart[itemCode].qty = cart[itemCode].qty + qty;
    } else {
      newCart[itemCode] = { qty: 1, price, name, size, variant };
    }

    setCart(newCart);
    saveCart(newCart);
  };

After that, we will create a variable name newCart, and the newCart is equal to cart, and add an if and else statement. It says that if an item is in the cart, addToCart will increment the quantity, and if not, then it will add the object name such as name, qty, price, size, and variant, then after setCart is newCart, and then we will save it by saveCart

We are using react-tostify for notification, and if you have not installed yet, then install it by using this command,

npm install --save react-toastify

Afterwards, we create another method clearCart then will implement the arrow function

const clearCart = () => {
    setCart({});
    saveCart({});
    toast.error('Cart Clear!', {
      position: "top-center",
      autoClose: 1500,
      hideProgressBar: true,
      closeOnClick: true,
      pauseOnHover: true,
      draggable: true,
      progress: undefined,
      theme: "light",
      });
  };

setCart will be an empty object {} because it will take time to set. And also saveCart will be an empty object{}

After that, we will create another object RemoveFromCart with the arrow function. We will create an object newCart and parse JSON.parse(JSON.strigyfy(cart));, which will select all the entities. And this feature is kind similar to the addToCart function, and it says that if an item is in the cart, then it will decrement the quantity,

const RemoveFromCart = (itemCode, qty, price, name, size, variant) => {
    let newCart = JSON.parse(JSON.stringify(cart));
    toast.warn('Item removed!', {
      position: "top-center",
      autoClose: 1500,
      hideProgressBar: true,
      closeOnClick: true,
      pauseOnHover: true,
      draggable: true,
      progress: undefined,
      theme: "light",
      });
    if (itemCode in cart) {
      newCart[itemCode].qty = cart[itemCode].qty - qty;
      if (newCart[itemCode].qty <= 0) {
        delete newCart[itemCode];
      }
    }
    setCart(newCart);
    saveCart(newCart);
  };

If not less than zero, then it will delete the itemCode, and it will set the setCart is newCart and also saveCart is newCart

Note:- an itemCode is an object,

Okay, let's create another method saveCart,

const saveCart = (myCart) => {
    localStorage.setItem("cart", JSON.stringify(myCart));
    let subt = 0;
    let keys = Object.keys(myCart);
    for (let i = 0; i < keys.length; i++) {
      subt += myCart[keys[i]].price * myCart[keys[i]].qty;
    }
    setSubTotal(subt);
  };

and the same will implement an arrow function

Afterwards, let's create another method name buyNow with an arrow function, and select all the objects, also create a variable name newCart,

const buyNow = (itemCode, qty, price, name, size, variant) => {
    let newCart = { itemCode: { qty: 1, price, name, size, variant } };
    setCart(newCart);
    saveCart(newCart);
    router.push("/checkout");
  };

After adding the objects, it will push to the checkout page with the help of react-router

Showing product using Effect

It says that if the item is already in the cart, show it to the user, and if not. Then you clear the localStorage, In the end, we are returning to the Navbar

import Footer from "@/components/Footer";
import Navbar from "@/components/Navbar";
import "@/styles/globals.css";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

export default function App({ Component, pageProps }) {
  const [cart, setCart] = useState({});
  const [subTotal, setSubTotal] = useState(0);
  const router = useRouter();

  useEffect(() => {
    console.log("load from app.js");
    try {
      if (localStorage.getItem("cart")) {
        setCart(JSON.parse(localStorage.getItem("cart")));
        saveCart(JSON.parse(localStorage.getItem("cart")));
      }
    } catch (error) {
      console.error(error);
      localStorage.clear();
    }
  }, []);

  const saveCart = (myCart) => {
    localStorage.setItem("cart", JSON.stringify(myCart));
    let subt = 0;
    let keys = Object.keys(myCart);
    for (let i = 0; i < keys.length; i++) {
      subt += myCart[keys[i]].price * myCart[keys[i]].qty;
    }
    setSubTotal(subt);
  };
  const addToCart = (itemCode, qty, price, name, size, variant) => {
    let newCart = cart;
    toast.success("Item added successfully!", {
      position: "top-center",
      autoClose: 1500,
      hideProgressBar: true,
      closeOnClick: true,
      pauseOnHover: true,
      draggable: true,
      progress: undefined,
      theme: "light",
    });
    if (itemCode in cart) {
      newCart[itemCode].qty = cart[itemCode].qty + qty;
    } else {
      newCart[itemCode] = { qty: 1, price, name, size, variant };
    }

    setCart(newCart);
    saveCart(newCart);
  };

  const buyNow = (itemCode, qty, price, name, size, variant) => {
    let newCart = { itemCode: { qty: 1, price, name, size, variant } };
    setCart(newCart);
    saveCart(newCart);
    router.push("/checkout");
  };

  const clearCart = () => {
    setCart({});
    saveCart({});
    toast.error('Cart Clear!', {
      position: "top-center",
      autoClose: 1500,
      hideProgressBar: true,
      closeOnClick: true,
      pauseOnHover: true,
      draggable: true,
      progress: undefined,
      theme: "light",
      });
  };

  const RemoveFromCart = (itemCode, qty, price, name, size, variant) => {
    let newCart = JSON.parse(JSON.stringify(cart));
    toast.warn('Item removed!', {
      position: "top-center",
      autoClose: 1500,
      hideProgressBar: true,
      closeOnClick: true,
      pauseOnHover: true,
      draggable: true,
      progress: undefined,
      theme: "light",
      });
    if (itemCode in cart) {
      newCart[itemCode].qty = cart[itemCode].qty - qty;
      if (newCart[itemCode].qty <= 0) {
        delete newCart[itemCode];
      }
    }
    setCart(newCart);
    saveCart(newCart);
  };

  return (
    <>
      <Navbar
        key={subTotal}
        cart={cart}
        addToCart={addToCart}
        RemoveFromCart={RemoveFromCart}
        clearCart={clearCart}
        subTotal={subTotal}
      />
      <ToastContainer
        position="top-center"
        autoClose={1500}
        limit={5}
        hideProgressBar
        newestOnTop
        closeOnClick
        rtl={false}
        pauseOnFocusLoss
        draggable
        pauseOnHover
        theme="light"
      />
      <Component
        cart={cart}
        addToCart={addToCart}
        buyNow={buyNow}
        RemoveFromCart={RemoveFromCart}
        clearCart={clearCart}
        subTotal={subTotal}
        {...pageProps}
      />
      <Footer />
    </>
  );
}

T-shirt Pages

creating a t-shirt.js file inside pages/ directory, and for further implementation, I'm giving you the GitHub Links. In the future, maybe I will complete this article