Try this way:
export function cartReducer(state = {}, action) {
switch (action.type) {
case ADD_TO_CART:
return {
...state,
[action.payload._id]: {
data: action.payload,
count: state[action.payload._id] ? state[action.payload._id].count + 1 : 1,
}
}
default:
return state;
}
}
Edit: Below a detailed answer your question in your comment
Let's assume you have already fetched data and your cartReducer
has the following value :
{
1: { data: { _id: 1, name: 'Evian Bottle 1L' }, count: 1 },
2: { data: { _id: 2, name: 'Coca Zero 1L' }, count: 1 },
}
1. The user adds for the first time the item 7Up 1L
in the cart. You dispatch the following action:
{
type: 'ADD_TO_CART',
payload: {
_id: 3,
name: '7Up 1L',
}
}
Here how your reducer will process the new value:
First step
return {
...state,
[action.payload._id]: {
data: action.payload,
count: state[action.payload._id] ? state[action.payload._id].count + 1 : 1,
}
}
Second step
return {
1: { data: { _id: 1, name: 'Evian 1L' }, count: 1 },
2: { data: { _id: 2, name: 'Coca Zero 1L' }, count: 1 },
[action.payload._id]: {
data: action.payload,
count: state[action.payload._id] ? state[action.payload._id].count + 1 : 1,
}
}
Third step
return {
1: { data: { _id: 1, name: 'Evian 1L' }, count: 1 },
2: { data: { _id: 2, name: 'Coca Zero 1L' }, count: 1 },
3: {
data: { _id: 3, name: '7Up 1L' },
count: state[3] ? state[3].count + 1 : 1,
}
}
Fourth step
return {
1: { data: { _id: 1, name: 'Evian 1L' }, count: 1 },
2: { data: { _id: 2, name: 'Coca Zero 1L' }, count: 1 },
3: {
data: { _id: 3, name: '7Up 1L' },
count: 1,
}
}
2.Now your user wants to add another 7Up 1L
in the cart. Dispatch of the action:
{
type: 'ADD_TO_CART',
payload: {
_id: 3,
name: '7Up 1L',
}
}
Your reducer:
First step
return {
...state,
[action.payload._id]: {
data: action.payload,
count: state[action.payload._id] ? state[action.payload._id].count + 1 : 1,
}
}
Second step
return {
1: { data: { _id: 1, name: 'Evian 1L' }, count: 1 },
2: { data: { _id: 2, name: 'Coca Zero 1L' }, count: 1 },
3: { data: { _id: 3, name: '7Up 1L' }, count: 1 },
[action.payload._id]: {
data: action.payload,
count: state[action.payload._id] ? state[action.payload._id].count + 1 : 1,
}
}
Third step
return {
1: { data: { _id: 1, name: 'Evian 1L' }, count: 1 },
2: { data: { _id: 2, name: 'Coca Zero 1L' }, count: 1 },
3: { data: { _id: 3, name: '7Up 1L' }, count: 1 },
3: {
data: { _id: 3, name: '7Up 1L' },
count: state[3] ? state[3].count + 1 : 1,
}
}
Fourth step
return {
1: { data: { _id: 1, name: 'Evian 1L' }, count: 1 },
2: { data: { _id: 2, name: 'Coca Zero 1L' }, count: 1 },
3: { data: { _id: 3, name: '7Up 1L' }, count: 1 },
3: {
data: { _id: 3, name: '7Up 1L' },
count: 1 + 1,
}
}
Fifth step
return {
1: { data: { _id: 1, name: 'Evian 1L' }, count: 1 },
2: { data: { _id: 2, name: 'Coca Zero 1L' }, count: 1 },
3: { data: { _id: 3, name: '7Up 1L' }, count: 1 },
3: {
data: { _id: 3, name: '7Up 1L' },
count: 2,
}
}
Sixth step
return {
1: { data: { _id: 1, name: 'Evian 1L' }, count: 1 },
2: { data: { _id: 2, name: 'Coca Zero 1L' }, count: 1 },
3: {
data: { _id: 3, name: '7Up 1L' },
count: 2,
}
}
Hope it helps.
Edit 2: Answer to your 2nd question in the comment: What happens when I want to remove items from the cart ?
1. The user removes the Evian 1L
from his cart. You dispatch the following action:
{
type: 'REMOVE_FROM_CART',
payload: {
_id: 1,
}
}
2. You reducer
export function cartReducer(state = {}, action) {
switch (action.type) {
case ADD_TO_CART:
return {
...state,
[action.payload._id]: {
data: action.payload,
count: state[action.payload._id] ? state[action.payload._id].count + 1 : 1,
}
}
case REMOVE_FROM_CART: {
const foundItem = state[action.payload._id];
if (foundItem && foundItem.count > 1) {
return {
...state,
[action.payload._id]: {
...foundItem,
count: foundItem.count - 1,
}
}
}
// In a immutable way - Avoid using the delete keyword
return Object
.keys(state)
.filter(key => key != _id)
.reduce((result, item) => ({ ...result, [item]: state[item] }), {});
}
default:
return state;
}
}
Edit 3: Answer to your 3rd question in the comment: What if the count has already reached 0 and we want to subtract one more item ?
The best way to do this would be:
Directly in the component: Before this dispatch, check if the count is already at 0.
- If so, don't trigger this dispatch but another one that would allow you to display this message.
- Otherwise, trigger it.
In the current reducer, with the written code in this answer, you won't be able to find this ID so nothing to change :)
Hope it helps!