Search code examples
reactjsjsxreact-contextreact-statereact-state-management

Trouble with react state and shopping cart


I have defined some react context for a shopping cart which I want to be able to access in every child component. I have also defined some methods (add to and remove from the shopping cart). I cannot get the addToCart function to work:

import React, { useContext, useState } from "react";

const ShoppingCartContext = React.createContext();

export function useShoppingCart() {
    return useContext(ShoppingCartContext);
}

export function ShoppingCartProvider({ children }) {
    const [shoppingCart, setShoppingCart] = useState([]);

    function addToCart(item) {
        setShoppingCart(shoppingCart.concat(item));
    }

    function removeFromCart(item) {
        const index = shoppingCart.indexOf(item);
        setShoppingCart(shoppingCart.splice(index, 1));
    }

    const value = { shoppingCart, setShoppingCart, addToCart, removeFromCart };

    return (
        <ShoppingCartContext.Provider value={value}>
            {children}
        </ShoppingCartContext.Provider>
    );
}

In the file I want to access the shopping cart in, I am doing this:

const { shoppingCart, setShoppingCart, addToCart, removeFromCart } = useShoppingCart();

Then, in a useEffect(), I am doing this:

addToCart(["item"])
console.log(shoppingCart)

But it console.logs an empty array:

enter image description here


Solution

  • So, assuming that useEffect is called after the initial render of your child component, the following happens

    addToCart(["item"])  // context state is [], a rerender with the new state is scheduled
    console.log(shoppingCart) // context state is [], an empty array is logged
    

    After this, the state updates and your child component rerenders. If you move your console.log out to the component body, you will see the change

    
    const MyShoppingCartConsumingComponent = () => {
      const { shoppingCart, setShoppingCart, addToCart, removeFromCart } = useShoppingCart();
      
      React.useEffect(() => {
         addToCart(['item'])
      }, [])
    
      console.log(shoppingCart)
    
      return <p>yo!</p>
    }
    

    Something like this will be logged

    
    []
    ['item']