0

I'm making a shopping cart and want to show the quantity of all items in the header of my website.

I use useReducer and context to store my items through my applicationand this works. But when I refresh everything is gone. So now I wanna store my quantity in the localStorage.

So if I add a new item to the card I check if quantity already excists in localStorage and add my new quantity to it. But somehow everything runs twice resulting in adding the double amount of intended.

sorry for my grammar english is not my first language

import { useReducer } from "react";

import CartContext from "./cart-context";

const defaultCartState = {
  items: [],
  totalAmount: 0,
  totalQuantity: 0,
};

const cartReducer = (state, action) => {
  if (action.type === "ADD") {
    const updatedTotalAmount =
      state.totalAmount + action.item.price * action.item.amount;

    if (JSON.parse(localStorage.getItem("quantity"))) {
      state.totalQuantity = JSON.parse(localStorage.getItem("quantity"));
    }

    console.log(state.totalQuantity);
    console.log(action.item.amount);

    const updatedTotalQuantity = state.totalQuantity + action.item.amount;

    const existingCartItemIndex = state.items.findIndex(
      (item) => item.id === action.item.id
    );
    const existingCartItem = state.items[existingCartItemIndex];
    let updatedItems;

    if (existingCartItem) {
      const updatedItem = {
        ...existingCartItem,
        amount: existingCartItem.amount + action.item.amount,
      };
      updatedItems = [...state.items];
      updatedItems[existingCartItemIndex] = updatedItem;
    } else {
      updatedItems = state.items.concat(action.item);
    }

    localStorage.setItem("quantity", JSON.stringify(updatedTotalQuantity));

    return {
      items: updatedItems,
      totalAmount: updatedTotalAmount,
      totalQuantity: updatedTotalQuantity,
    };
  }

  return defaultCartState;
};

CartProvider

const CartProvider = (props) => {
  const [cartState, dispatchCartAction] = useReducer(
    cartReducer,
    defaultCartState
  );

  const addItemToCartHandler = (item) => {
    dispatchCartAction({ type: "ADD", item: item });
  };

  const removeItemFromCartHandler = (id) => {
    dispatchCartAction({ type: "REMOVE", id: id });
  };

  const cartContext = {
    items: cartState.items,
    totalAmount: cartState.totalAmount,
    totalQuantity: cartState.totalQuantity,
    addItem: addItemToCartHandler,
    removeItem: removeItemFromCartHandler,
  };

  return (
    <CartContext.Provider value={cartContext}>
      {props.children}
    </CartContext.Provider>
  );
};

export default CartProvider;

The console where you see it running twice: Screenshot of console

RubenSmn
  • 4,091
  • 2
  • 5
  • 24
Vos
  • 3
  • 3

1 Answers1

0

try to set the value from localstorage only once when you create a context and pass a default state to it like this:

import { useContext, useReducer, createContext } from 'react'

const defaultCartState = {
  items: [],
  totalAmount: 0,
  totalQuantity: JSON.parse(localStorage.getItem('quantity')) ?? 0,
}

const CartContext = createContext(defaultCartState)

const cartReducer = (state, action) => {
  if (action.type === 'ADD') {
    const updatedTotalAmount = state.totalAmount + action.item.price * action.item.amount

    const updatedTotalQuantity = state.totalQuantity + action.item.amount

    const existingCartItemIndex = state.items.findIndex((item) => item.id === action.item.id)
    const existingCartItem = state.items[existingCartItemIndex]
    let updatedItems

    if (existingCartItem) {
      const updatedItem = {
        ...existingCartItem,
        amount: existingCartItem.amount + action.item.amount,
      }
      updatedItems = [...state.items]
      updatedItems[existingCartItemIndex] = updatedItem
    } else {
      updatedItems = state.items.concat(action.item)
    }

    localStorage.setItem('quantity', JSON.stringify(updatedTotalQuantity))

    return {
      items: updatedItems,
      totalAmount: updatedTotalAmount,
      totalQuantity: updatedTotalQuantity,
    }
  }

  if (action.type === 'REMOVE') {
    const existingCartItem = state.items.find((item) => item.id === action.id)
    console.log('stas', action.id, existingCartItem)
    const updatedTotalAmount = state.totalAmount - existingCartItem.price * existingCartItem.amount

    const updatedTotalQuantity = state.totalQuantity - existingCartItem.amount

    const updatedItems = state.items.filter((item) => item.id !== action.id)

    localStorage.setItem('quantity', JSON.stringify(updatedTotalQuantity))

    return {
      items: updatedItems,
      totalAmount: updatedTotalAmount,
      totalQuantity: updatedTotalQuantity,
    }
  }

  return defaultCartState
}

const CartProvider = (props) => {
  const [cartState, dispatchCartAction] = useReducer(cartReducer, defaultCartState)

  const addItemToCartHandler = (item) => {
    dispatchCartAction({ type: 'ADD', item: item })
  }

  const removeItemFromCartHandler = (id) => {
    dispatchCartAction({ type: 'REMOVE', id: id })
  }

  const cartContext = {
    items: cartState.items,
    totalAmount: cartState.totalAmount,
    totalQuantity: cartState.totalQuantity,
    addItem: addItemToCartHandler,
    removeItem: removeItemFromCartHandler,
  }

  // eslint-disable-next-line react/prop-types
  return <CartContext.Provider value={cartContext}>{props.children}</CartContext.Provider>
}

const My = () => {
  const { addItem, items, removeItem, totalAmount, totalQuantity } = useContext(CartContext)
  console.log('context', addItem, items, removeItem, totalAmount, totalQuantity)
  return (
    <div>
      <div>
        items:{' '}
        {items.map((item, i) => (
          <div key={i}>{JSON.stringify(item)}</div>
        ))}
      </div>
      <div>totalAmount: {totalAmount}</div>
      <div>totalQuantity: {totalQuantity}</div>
      <button onClick={() => addItem({ price: 3, amount: 1, id: 2 })}>add</button>
      <button onClick={() => removeItem(2)}>remove</button>
    </div>
  )
}
const App = () => {
  return (
    <CartProvider>
      <My />
    </CartProvider>
  )
}

export default App
stasdes
  • 669
  • 3
  • 10
  • When I try this I get an localStorage is not defined error on line 6 in de defaultCartState const. – Vos Jan 05 '23 at 14:31
  • take a look here on how to resolve it: https://stackoverflow.com/questions/52474208/react-localstorage-is-not-defined-error-showing – stasdes Jan 08 '23 at 08:13