Home > Software design >  Redux state changes but not reflected in component
Redux state changes but not reflected in component

Time:09-23

I'm trying to implement a shopping cart using redux. here is my cart-reducer:

export const cartReducer = (
state = { cartItems: JSON.parse(localStorage.getItem("cartItems") || "[]")},
action) => {
switch (action.type) {
 case ADD_TO_CART:
  return { ...state,cartItems: action.payload };
}}

Here is the component where I want to show the updated state value accessing it using props in connect and update the cartItems.length after every state update

class Cartsidebar extends Component {
    constructor(props) {
        super(props);
        this.state = {
            grandTotal: '',toggle:true
        }
    }
    handleHide(){
        this.setState({ toggle: !this.state.toggle})
    }
    render() {
        
     const {cartItems}=this.props;
     console.log(cartItems);
        return (
            <div>
               {cartItems.length}

            </div>
        )
    }
}

export default connect(
    (state) => ({
        cartItems: state.cart.cartItems,
    }),
    { incrementToCart, decreaseToCart, removeFromCart }
)(Cartsidebar);

States are updating fine and state-difference is also showing in redux-dev-tools on every update of redux state but it is not reflecting in cart component.what am i doing wrong here?Thanks in advance.

EDIT: this is function that execute on add to cart button onclick event:

handleAddToCart=(p)=>{
const cartItems = store.getState().cart.cartItems;
  let alreadyExists = false;
  cartItems.forEach((x) => {
    if (x.discountPer === p.discountPer) {
      alreadyExists = true;
    }
  });
  if (!alreadyExists) {
    cartItems.push({ ...p });
  }


store.dispatch(addToCart(cartItems));
     
}

And addToCart action creator looks like this:

export const addToCart = (cartItem) => {
  return({
    type: ADD_TO_CART,
    payload: cartItem,
  });
};

CodePudding user response:

What you are doing in handleAddToCart is a big no no, and goes against the pattern that Redux tries to enforce. I made some changes to your logic to make it easier, and updated the reducer. In theory, if you make these changes, it should work.

handleAddToCart:

handleAddToCart = (p) => {
  const cartItems = store.getState().cart.cartItems;

  for (const item of cartItems) {
    if (item.discountPer === p.discountPer) {
      return;
    }
  }

  store.dispatch(addToCart({ ...p }));
};

reducer:

export const cartReducer = (
  state = { cartItems: JSON.parse(localStorage.getItem("cartItems") || "[]") },
  action
) => {
  switch (action.type) {
    case ADD_TO_CART:
      return { ...state, cartItems: [...state.cartItems, action.payload] };
  }
};

CodePudding user response:

Issues

  1. You are mutating the state object. You are accessing a reference to the cart array in state and directly pushing into it.
  2. You aren't leveraging the power of Redux and reducers properly.

code

handleAddToCart = (p) => {
  const cartItems = store.getState().cart.cartItems; // cartItems is reference to state
  let alreadyExists = false;
  cartItems.forEach((x) => {
    if (x.discountPer === p.discountPer) {
      alreadyExists = true;
    }
  });
  if (!alreadyExists) {
    cartItems.push({ ...p }); // mutation!!
  }

  store.dispatch(addToCart(cartItems));
}

Solution

Pass the item you want to add to the cart in the action and move all the logic to update the cart into your reducer.

UI

handleAddToCart = (p) => {
  this.props.addToCart(p);
}

...

export default connect(
  (state) => ({
    cartItems: state.cart.cartItems,
  }),
  { addToCart, incrementToCart, decreaseToCart, removeFromCart }
)(Cartsidebar);

reducer

case ADD_TO_CART:
  const { payload } = action;
  const found = state.cartItems.find(item => item.discountPer === payload.discountPer);

  if (found) {
    return state;
  }

  return {
    ...state,
    cartItems: state.cartItems.concat(payload),
  };
  • Related