Search code examples
reactjsreduxreact-reduxreact-propsredux-reducers

Redux state changes but not reflected in component


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,
  });
};

Solution

  • 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),
      };