skip to Main Content

I am trying to create a shopping cart. I have created a context and passed the state as a value on pressing increment and decrement button on the cart my items count in the are changing but total number of items in the cart is not changing when I use the same context in navbar component. I am attaching the code snippets below

This is where I create my context

const initialState:initialType = {
  cartItems:cartItems,
  totalItems:cartItems.reduce((accumulator, object) => {
    return accumulator + object.quantity
  }, 0),
  totalAmount:0
}

export const CartContext = createContext<initialType|null>(initialState);

This down below is my provider for useContext.

<CartContext.Provider value={{...state}}>
<ContextCart removeItems={removeItems} increment={increment} decrement={decrement}/> </CartContext.Provider>

The value of state is coming from useReducer which is updating everything fine

this is how I used my useContext Hook in Navbar to fetch total number of Items in cart

const cartItems = useContext(CartContext);

return (
  <div>{cartItems.totalItems}</div>`
)

but whenever the state changes the navbar never re-renders with updated total number of items in cart kindly help me out.

This is my useReducer Function and its updating everthing well. I have checked its functionality by performing console.log(). and it is returning everything well, which also includes state.totalItems.

    
        type actionType={
      type:string,
      payload:string
    }
    export const reducer = (state:initialType ,action:actionType) => {
      if(action.type === "Delete" ){
        return {
          ...state,
          cartItems:state.cartItems.filter((currentElement)=>{
            return currentElement.id != action.payload
          })
        }
      }
       if (action.type === 'increment'){
          state.cartItems.forEach((element)=>{
            if (element.id === action.payload){
              element.quantity++;
              state.totalItems++
            }
          })
         
          return {...state};
          
      }
      if (action.type === 'decrement'){
        state.cartItems.forEach((element)=>{
          if (element.id === action.payload){
            element.quantity--;
            state.totalItems--;
          }
        })
        console.log(state)
        return {...state};
      }
      return {...state};
    }```

2

Answers


  1. The hiccup you’re experiencing might be because your totalItems isn’t updating when your cartItems state changes.

    You see, you’re calculating totalItems only once, during the initial state setup. So, even if cartItems changes later, totalItems doesn’t get recalculated.

    A simple fix could be moving the totalItems calculation into your reducer function. This way, it gets recalculated every time an action is dispatched.

    function cartReducer(state, action) {
      // your action cases here...
    
      // After performing the action, recalculate totalItems
      const totalItems = state.cartItems.reduce((accumulator, object) => {
        return accumulator + object.quantity
      }, 0);
    
      return {
        ...state,
        totalItems,
      };
    }
    

    Don’t forget to dispatch the ‘INCREMENT’ and ‘DECREMENT’ actions in your increment and decrement functions.

    With this tweak, your totalItems should stay in sync with the cartItems, and your Navbar should update correctly. Give it a shot!

    Login or Signup to reply.
  2. When you’re using useReducer, it gives you back the current state, right? And in your case, that state is an object. So, you can just grab totalItems straight from that state object. For example:

    const [state, dispatch] = useReducer(cartReducer, initialState);
    
    // Here's where we get totalItems from the state
    const { totalItems } = state;
    

    So, with this, totalItems is pulled right out of the state object, and you can use it wherever you need it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search