jenn hi
jenn hi

Reputation: 51

React/Redux shopping cart not updating

I'm learning how to build a very simple shopping cart by hand by looking at examples, and managed to get something up on my sample site with no errors. Here's the cart component:

import React, { Component } from 'react';
import { connect } from 'react-redux';

class Cart extends Component{
    render() {
        return (
            <div>
                {this.props.items.length}
            </div>
        )
    }
}
const mapStateToProps = (state) => {
    return {
        items: state.items
    }
}

export default connect(mapStateToProps)(Cart);

When someone clicks a button on another component, it's supposed to run what's in the reducer:

const initialState = {
    items : []
}

const cartReducer = (state = initialState, action) => {
    const newState = {...state};
    switch(action.type) {
        case "ADD_TO_CART":
            newState.items.push(action.item);
            break;
        default:
            return newState;
    }
    return newState;
}

export default cartReducer;

However, I'm unable to see the cart's this.props.items.length increase whenever I click the button, even though I can log the items array in the console and see it being added to. Does anyone have any suggestions on how to fix this? I can provide more code if necessary.

Upvotes: 0

Views: 619

Answers (1)

Linda Paiste
Linda Paiste

Reputation: 42188

Your component doesn't re-render because this.props.items is the same array as before. You haven't actually updated your state to have a new, modified array.

What you have done is something that you should definitely not do, which is to mutate the existing state. newState.items is the same array as state.items because newState copies all of the properties of state. You cannot call push() on it because push is a mutating operation.

You need to create a copy of the array, either with spread syntax or with concat().

const cartReducer = (state = initialState, action) => {
    switch(action.type) {
        case "ADD_TO_CART":
            return {
                ...state,
                items: state.items.concat(action.item)
            }
        default:
            return state;
    }
}

You can also use the Redux Toolkit helper library which makes life easier by allowing you to write reducers with mutations.

const cartSlice = createSlice({
  name: "cart",
  initialState: {
    items: []
  },
  reducers: {
    addToCart(state, action) {
      state.items.push(action.payload)
    },
  }
});

// action creator functions
export const { addToCart } = cartSlice.actions;

// reducer
export default cartSlice.reducer;

Upvotes: 1

Related Questions