Reputation: 51
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
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