You’re duplicating the functionality. You have a getter and a setter (total, setCartTotal). You wrap setCartTotal in another function (addToCart). Those you have added into the context.
The entire point of context is to avoid manually passing props down. So when you useContext
, you’ve got access to the getter and setter: the references you get from useContext
are the ones you should be using. But instead of using those, you’re passing the getter and setter manually down as props. So you have a conflict, and as a result, nothing happens.
It’s also a very bad idea to call your context CreateContext
given that the name of the function you use to create contexts is called createContext
but 🤷
EDIT: example. I’ve purposely made this slightly more complex than it is at the minute in an attempt to reflect a little bit more of a real-world situation. The issue is that Context makes things quite complicated, and needs to be used with care – it’s designed to pass things down anywhere in the app, so in your example, where there is only one level, it is much easier and safer to just pass props directly (I do realise you’re just testing out how it all works though, that it’s necessary for you to do it the way you’re doing it).
import React from "react";
import { CartProvider } from "./use-cart";
import AddToCart from "./AddToCart";
import CartTotalItems from "./CartTotalItems";
export default function App() {
return (
<CartProvider>
<CartTotalItems />
<AddToCart />
</CartProvider>
);
}
Split out the context, otherwise you have circular dependencies (in yours, App depends on Test which depends on App, which depends on Test etc – it’ll work but you’ll get warnings in the console)
import React from "react";
/**
* All the logic for carts goes in here. As it gets more complex, you would
* normally split the state and the functions for updating the state into two
* contexts (like CartStateContext and CartUpdateContext for example), and
* possibly start looking at `useReducer` instead of just `useState`, as there
* is stuff you need to think about like price calculations, error handling, maybe
* API calls _etc_ _etc_.
*/
const CartContext = React.createContext(null);
export const CartProvider = ({ children }) => {
const [cartTotal, setCartTotal] = React.useState(0);
const incrementCartTotal = () => setCartTotal(cartTotal + 1);
return (
<CartContext.Provider value={{ cartTotal, incrementCartTotal }}>
{children}
<CartContext.Provider>
);
// In a more complex situation, the cart Provider would contain both the providers, one of
// which would just have the state then inside that one would just have the update functions:
// <CartStateContext.Provider value={stateObject}>
// <CartUpdateContext.Provider value={updateFunctions}>
// {children}
// <CartUpdateContext.Provider>
// <CartStateContext.Provider>
};
// And in more complex situations, you would probably want to have have two hooks, a
// `useCartState` and `useUpdateCartState`
export const useCart = () => {
const { cartTotal, incrementCartTotal } = React.useContext(CartContext);
// Here you could put some error handling to prevent this hook being used when it
// isn't in the scope of the context.
return { cartTotal, incrementCartTotal };
}
import React from "react";
import { useCart } from "./use-cart";
const AddToCart = () => {
const { incrementCartTotal } = useCart();
return <button onClick={incrementCartTotal}>Add to cart</button>
};
export default AddToCart;
import React from "react";
import { useCart } from "./use-cart";
const CartTotalItems = () => {
const { cartTotal } = useCart();
return <p>Total items currently in cart: {cartTotal}</p>
};
export default CartTotalItems;