Search code examples
javascriptreactjsecmascript-6cart

Updating useContext after adding new value to an object in the array


I have a shopping cart that I want to update with new values depending on user choice from select/option. When the user selects quantity my useEffect triggers and the new value is added to my object (to exact child element that is used).

function ProductData({ price, id }) {
  const [itemsInCart, setItemsInCart] = useContext(ItemsInCartContext);
  const quantity = [1, 2, 3, 4, 5, 6, 7];
  const [chosenQuantity, setChosenQuantity] = useState(1);

  const quantityHandler = (quantity) => {
    setChosenQuantity(quantity.target.value);
  };

  useEffect(() => {
    const updateProductValue = () => {
      const item = itemsInCart.find((item) => item.listing_id === id);

      item.value = chosenQuantity * price;
    };
    updateProductValue();
    // How to update itemsInCart array of objects with new item value?
  }, [chosenQuantity]);

  return (
    <>
      <Quantity>
        Quantity:
        <Select value={chosenQuantity} onChange={(e) => quantityHandler(e)}>
          {quantity.map((number) => (
            <option key={Math.random()} value={number}>
              {number}
            </option>
          ))}
        </Select>
      </Quantity>
      <Price>${price}</Price>
    </>
  );
}

Now my edited object is not stored in local storage (useContext). How can I update my ItemsInCartContext in useEffect so the new value stays in the cart?


Solution

  • You need to keep state immutable, and also call setItemsInCart so set it, the straight forward way is mapping the target item id:

    useEffect(() => {
      setItemsInCart((prev) => {
        const newItems = prev.map((item) => {
          if (item.listing_id !== id) return item;
          return {
            ...item,
            value: chosenQuantity * price,
          };
        });
    
        return newItems;
      });
    }, [chosenQuantity]);