Reputation: 306
So I basically started learning Redux and wanted to create a simple store app where you can add the phones to the cart. I have created a state object and within it, I have created an array with objects with a list of items in the store. I wanted to update on [+] click the number of items ordered but it doesn't work for now. I have been struggling with that for 1 hour already and still do not see where the problem might be.
Reducer looks like that:
const initialState = {
liked:0,
cart:0,
item: [
{
id:1,
name: 'Iphone 8',
price: 2000,
desc: 'The new Iphone 8 available at our store!',
orderedNum: 0
},
{
id:2,
name: 'Iphone 6',
price: 1500,
desc: 'The new Iphone 6 available at our store!',
orderedNum: 0
},
{
id:3,
name: 'Samsung S8',
price: 2200,
desc: 'The new Samsung S8 available at our store!',
orderedNum: 0
},
{
id:4,
name: 'Xiaomi Mi 6',
price: 1400,
desc: 'The new Xiaomi Mi 6 available at our store!',
orderedNum: 0
},
{
id:5,
name: 'Pocophone P1',
price: 2100,
desc: 'The new Pocophone P1 available at our store!',
orderedNum: 0
},
{
id:6,
name: 'Nokia 3310',
price: 999,
desc: 'The new Nokia 3310 available at our store!',
orderedNum: 0
},
]
}
const reducer = (state = initialState, action) => {
const newState = {...state};
switch(action.type) {
case 'ADD_NUM':
return state.item.map((el, index) => {
if(el.id === action.id ){
return {
...el,
orderedNum: el.orderedNum + 1
}
}
return el;
})
default:
break;
}
return newState;
}
export default reducer;
I have the action:
const mapStateToProps = state => {
return {
item: state.item
}
}
const mapDispatchToProps = dispatch => {
return {
addNum: () => dispatch ({
type: 'ADD_NUM',
id: this.props.id,
value: 1
})
}
I have tried it in a different ways but I believe it could be the problem with nesting in the reducer.
Could someone advise?
Upvotes: 3
Views: 2382
Reputation: 4011
Your reducer should look something like this:
export default (state = initialState, action) => {
switch (action.type) {
case 'ADD_ITEM':
return [...state, action.item];
case 'REMOVE_ITEM':
return state.filter(({ id }) => id !== action.id);
default:
return state;
}
};
As pointed out in the comments the above will work for an initial state that is an array but not an object... Here is how to handle it if it's an object (with two helper methods from lodash mapKeys
and omit
:
export default (state = {}, action) => {
switch (action.type) {
case FETCH_ITEMS:
return { ...state, ...mapKeys(action.payload, 'id') };
case FETCH_ITEM:
return { ...state, [action.payload.id]: action.payload };
case CREATE_ITEM:
return { ...state, [action.payload.id]: action.payload };
case EDIT_ITEM:
return { ...state, [action.payload.id]: action.payload };
case DELETE_ITEM:
return omit(state, action.payload);
default:
return state;
}
};
Upvotes: 1
Reputation: 11760
Lets start with your reducer
const reducer = (state = initialState, action) => {
switch (action.type) {
case "ADD_NUM":
return {
// destruct and return a new object otherwise react wont update the UI
...state,
item: state.item.map(el =>
el.id === action.id
? { ...el , orderedNum: el.orderedNum + action.value }
: el
)
};
default:
return state;
}
};
mapDispatchToProps
const mapDispatchToProps = dispatch => {
return {
// add id to addNum
addNum: id =>
dispatch({
type: "ADD_NUM",
id,
value: 1
})
};
};
Items component
const Items = ({ item, addNum }) => (
item.map(el => (
<div key={el.id}>
<h1>{el.name}</h1>
<h3>{el.price}</h3>
<h3>{`orderedNum: ${el.orderedNum}`}</h3>
// add the id to addNum
<button onClick={() => addNum(el.id)}>+</button>
</div>
))
);
Upvotes: 2