Search code examples
reactjsreact-context

How to update 'total' using 'setTotal' in my shopping cart react app?


Here are Components of REACT Cart App

App.jsx

import "bootstrap/dist/css/bootstrap.css";

import Cart from "./Cart";
import { CartProvider } from "./CartContext";

import "./App.css";

function App() {
  return (
    <CartProvider>
      <Cart />
    </CartProvider>
  );
}

export default App;

CartContext.jsx

import { createContext, useState } from "react";
import { data } from "./Data";

const CartContext = createContext();

export const CartProvider = ({ children }) => {
  const [total, setTotal] = useState(0);
  return (
    <CartContext.Provider value={{ total, setTotal, data }}>
      {children}
    </CartContext.Provider>
  );
};

export default CartContext;

Cart.jsx

import React from "react";
import Item from "./Item";
import { useContext } from "react";
import CartContext from "./CartContext";

function Cart() {
  const { data, total } = useContext(CartContext);

  return (
    <div className="container">
      <div className="row">
        <div className="col-md-12 text-center m-3 ">
          <h1>Your Cart Items</h1>
        </div>
      </div>
      <div className="row">
        <div className="col-7 text-center border border-black">
          <table className="table align-middle p-2 ">
            <thead>
              <tr>
                <th scope="col">Product</th>
                <th scope="col">Price</th>
                <th scope="col">Qty</th>
                <th scope="col">Subtotal</th>
              </tr>
            </thead>
            <tbody>
              {data.map((product) => {
                return <Item key={product.id} product={product} />;
              })}
            </tbody>
          </table>
        </div>
        <div
          className="col-4 ms-2  border border-black"
          style={{ height: 300 }}
        >
          <h4 className="p-2">Total: {total}</h4>
        </div>
      </div>
    </div>
  );
}

export default Cart;

Item.jsx

import React, { useEffect } from "react";
import { useState } from "react";
import CartContext from "./CartContext";
import { useContext } from "react";

function Item({ product }) {
  const { id, img, price } = product;
  const [qty, setQty] = useState(1);
  const [subTotal, setSubTotal] = useState(price);
  const { setTotal } = useContext(CartContext);

  

  const handleQtyDecmnt = () => {
    qty > 1 && [
      setQty((qty) => qty - 1),
      setSubTotal((subTotal) => subTotal - price),
    ];
  };

  const handleQtyIncremnt = () => {
    [setQty((qty) => qty + 1), setSubTotal((subTotal) => subTotal + price)];
  };

  return (
    <tr>
      <td>
        <img className="img-fluid" src={img} alt="" style={{ width: 100 }} />
      </td>
      <td>&#8377;{price}</td>
      <td>
        <div className=" border border-2 rounded">
          <button
            onClick={handleQtyDecmnt}
            type="button"
            className="border-0  bg-white me-2 fs-3 "
          >
            -
          </button>
          {qty}
          <button
            onClick={handleQtyIncremnt}
            type="button"
            className="border-0  bg-white ms-2  fs-3"
          >
            +
          </button>
        </div>
      </td>
      <td>&#8377;{subTotal}</td>
    </tr>
  );
}

export default Item;

Data.js

export const data = [
  {
    id: 1,
    img: "https://m.media-amazon.com/images/I/413OgI8KzuL._SY445_SX342_.jpg",
    price: 148.0,
  },
  {
    id: 2,
    img: "https://m.media-amazon.com/images/I/41N4kMdg33L._SY445_SX342_.jpg",
    price: 181.0,
  },
  {
    id: 3,
    img: "https://m.media-amazon.com/images/I/515RbDiix5L._SY342_.jpg",
    price: 149.0,
  },
  {
    id: 4,
    img: "https://m.media-amazon.com/images/I/41CnSAh+qkL._SY445_SX342_.jpg",
    price: 1327,
  },
  {
    id: 5,
    img: "https://m.media-amazon.com/images/I/41SzG3Zae4L._SY445_SX342_.jpg",
    price: 249.0,
  },
];

I would like update my cart's total amount using 'total'. When I try to use useState hook such as ,

const {total, setTotal} = useContext(CartContext)

useEffect((total)=>{total + subTotal}, [])

In that way, the total amount goes to an unpredictable way? How to update this total using the useState and useEffect hooks


Solution

  • You're misusing useEffect, check the useEffect docs to understand how and why to use it (spoiler: most of the time it's not necessary); and must call setTotal to update the total state.

    In your case, I'm not sure when you want to trigger that update, but define a handler like the one below and call it on the event that should trigger the update (like done on onClick on other files here):

    const {setTotal} = useContext(CartContext)
    
    const handleTotalUpdate = () => {
       setTotal(previousTotal => previousTotal + subTotal)
    }